* [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus
@ 2018-12-14 22:47 Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
` (29 more replies)
0 siblings, 30 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
The Mesh Daemon has been largely rewritten.
It matches the API in doc/mesh-api.txt, and is now accessible
from non-privledged DBus clients. The commandline version has
been temporarily removed, although it will probably be re-added
in the future. The dBus privledges need to be adjusted to allow
for non-privledged access to Daemon interfaces. We will shortly
also be adding a Mesh Specific README and TODO file, but in
the meantime, contact Brian and/or Inga with any questions.
Brian Gix (12):
mesh: Staging for Mesh DBus API rewrite
mesh: Delete obsolete files
mesh: Rewite Network layer for multiple nodes
mesh: Direction agnostic PB-Adv implimentation
mesh: Acceptor side provisioning implimentation
mesh: Initiator side provisioning implimentation
mesh: Rewrite Controler interface for full init
mesh: Unchanged variables set to const
mesh: re-arrange provisioning for DBus API
mesh: restructure I/O for multiple nodes
mesh: Clean-up Comment style
mesh: Enable building Mesh Daemon
Inga Stotland (18):
mesh: Utilities for DBus support
mesh: Internal errors
mesh: Re-write storage for Multiple Nodes
mesh: Rewrite Node handling for multiple nodes
mesh: centralize generic utilities
mesh: Re-architect for DBus API
mesh: Make config model handle multiple nodes
mesh: Multi node Config Server model
mesh: Restrusture DB to support multiple nodes
mesh: restructure model services for multiple nodes
mesh: DBUS interface for Provisioning Agent
mesh: restructure App Key storage
mesh: Update for DBus API and multi-node support
mesh: Add default location for Mesh Node storage
mesh: Add structural changes to for mesh
mesh: Sample Provisioning Agent
mesh: Sample On/Off Client and Server
mesh: Sample Mesh Joiner (provision acceptor)
Makefile.mesh | 27 +-
configure.ac | 5 +
mesh/agent.c | 665 ++++++++++++++++----
mesh/agent.h | 71 ++-
mesh/appkey.c | 17 +-
mesh/cfgmod-server.c | 173 +++---
mesh/cfgmod.h | 2 +-
mesh/config/composition.json | 44 --
mesh/dbus.c | 181 ++++++
mesh/dbus.h | 40 ++
mesh/display.c | 64 --
mesh/error.h | 35 ++
mesh/friend.c | 76 +--
mesh/main.c | 73 ++-
mesh/mesh-db.c | 454 +++++++++-----
mesh/mesh-db.h | 6 +-
mesh/mesh-io-api.h | 2 +-
mesh/mesh-io-generic.c | 148 ++++-
mesh/mesh-io.c | 3 +-
mesh/mesh-io.h | 3 +-
mesh/mesh.c | 625 ++++++++++++++-----
mesh/mesh.h | 27 +-
mesh/model.c | 811 +++++++++++++++++-------
mesh/model.h | 66 +-
mesh/net.c | 293 +++------
mesh/net.h | 31 +-
mesh/node.c | 1338 +++++++++++++++++++++++++++++++++-------
mesh/node.h | 42 +-
mesh/pb-adv.c | 444 +++++++++++++
mesh/{display.h => pb-adv.h} | 13 +-
mesh/prov-acceptor.c | 711 +++++++++++++++++++++
mesh/prov-initiator.c | 651 +++++++++++++++++++
mesh/prov.c | 722 ----------------------
mesh/prov.h | 14 +-
mesh/provision.c | 1162 ----------------------------------
mesh/provision.h | 112 +++-
mesh/storage.c | 574 ++++++++---------
mesh/storage.h | 39 +-
mesh/test/agent.py | 40 ++
mesh/test/example-onoff-client | 288 +++++++++
mesh/test/example-onoff-server | 365 +++++++++++
mesh/test/test-join | 408 ++++++++++++
mesh/util.c | 26 +
mesh/util.h | 1 +
44 files changed, 7192 insertions(+), 3700 deletions(-)
delete mode 100644 mesh/config/composition.json
create mode 100644 mesh/dbus.c
create mode 100644 mesh/dbus.h
delete mode 100644 mesh/display.c
create mode 100644 mesh/error.h
create mode 100644 mesh/pb-adv.c
rename mesh/{display.h => pb-adv.h} (71%)
create mode 100644 mesh/prov-acceptor.c
create mode 100644 mesh/prov-initiator.c
delete mode 100644 mesh/prov.c
delete mode 100644 mesh/provision.c
create mode 100755 mesh/test/agent.py
create mode 100644 mesh/test/example-onoff-client
create mode 100644 mesh/test/example-onoff-server
create mode 100644 mesh/test/test-join
--
2.14.5
^ permalink raw reply [flat|nested] 31+ messages in thread
* [PATCH BlueZ 01/30] mesh: Staging for Mesh DBus API rewrite
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 02/30] mesh: Delete obsolete files Brian Gix
` (28 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
Makefile.am | 1 -
1 file changed, 1 deletion(-)
diff --git a/Makefile.am b/Makefile.am
index f84a1faba..7e92977b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -303,7 +303,6 @@ unit_tests =
include Makefile.tools
include Makefile.obexd
include android/Makefile.am
-include Makefile.mesh
if HID2HCI
rulesdir = $(UDEV_DIR)/rules.d
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 02/30] mesh: Delete obsolete files
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 03/30] mesh: Utilities for DBus support Brian Gix
` (27 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/config/composition.json | 44 --
mesh/display.c | 64 ---
mesh/display.h | 28 -
mesh/prov.c | 722 --------------------------
mesh/provision.c | 1162 ------------------------------------------
5 files changed, 2020 deletions(-)
delete mode 100644 mesh/config/composition.json
delete mode 100644 mesh/display.c
delete mode 100644 mesh/display.h
delete mode 100644 mesh/prov.c
delete mode 100644 mesh/provision.c
diff --git a/mesh/config/composition.json b/mesh/config/composition.json
deleted file mode 100644
index 20c0d0c3a..000000000
--- a/mesh/config/composition.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "$schema":"file:\/\/\/BlueZ\/MeshD\/local_schema\/mesh.jsonschema",
- "meshName":"BT Mesh sample node",
- "UUID":"E0ED0F0200000000203C100200000000",
- "cid":"0002",
- "pid":"0010",
- "vid":"0001",
- "crpl":"000a",
- "proxy":"unsupported",
- "friend":"disabled",
- "lowPower":"disabled",
- "relay":{
- "mode":"enabled"
- },
- "elements":[
- {
- "elementIndex":0,
- "location":"0001",
- "models":[
- {
- "modelId":"0000"
- },
- {
- "modelId":"1001"
- }
- ]
- }
- ],
- "provision": {
- "privateKey": "729aa0670d72cd6497502ed473502b037e8803b5c60829a5a3caa219505530ba",
- "algorithms": [ 0 ],
- "inputOOB": {
- "size": 8,
- "actions": [ 2, 3]
- },
- "outputOOB": {
- "size": 8,
- "actions": [ 3, 4]
- },
- "publicType": false,
- "staticType": false
- },
- }
-}
diff --git a/mesh/display.c b/mesh/display.c
deleted file mode 100644
index 8238ae849..000000000
--- a/mesh/display.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2018 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.
- *
- */
-
-#include <stdio.h>
-#include <unistd.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <ell/ell.h>
-
-#include "display.h"
-
-static unsigned int cached_num_columns;
-
-unsigned int num_columns(void)
-{
- struct winsize ws;
-
- if (cached_num_columns > 0)
- return cached_num_columns;
-
- if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0 || ws.ws_col == 0)
- cached_num_columns = 80;
- else
- cached_num_columns = ws.ws_col;
-
- return cached_num_columns;
-}
-
-void print_packet(const char *label, const void *data, uint16_t size)
-{
- struct timeval pkt_time;
-
- gettimeofday(&pkt_time, NULL);
-
- if (size > 0) {
- char *str;
-
- str = l_util_hexstring(data, size);
- l_debug("%05d.%03d %s: %s",
- (uint32_t) pkt_time.tv_sec % 100000,
- (uint32_t) pkt_time.tv_usec/1000, label, str);
- l_free(str);
- } else
- l_debug("%05d.%03d %s: empty",
- (uint32_t) pkt_time.tv_sec % 100000,
- (uint32_t) pkt_time.tv_usec/1000, label);
-}
diff --git a/mesh/display.h b/mesh/display.h
deleted file mode 100644
index f5d1f7f79..000000000
--- a/mesh/display.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2018 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 COLOR_OFF "\x1B[0m"
-#define COLOR_RED "\x1B[0;91m"
-#define COLOR_GREEN "\x1B[0;92m"
-#define COLOR_YELLOW "\x1B[0;93m"
-#define COLOR_BLUE "\x1B[0;94m"
-
-unsigned int num_columns(void);
-
-void print_packet(const char *label, const void *data, uint16_t size);
diff --git a/mesh/prov.c b/mesh/prov.c
deleted file mode 100644
index 45ced404c..000000000
--- a/mesh/prov.c
+++ /dev/null
@@ -1,722 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2018 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 "mesh/mesh-defs.h"
-
-#include "mesh/mesh-io.h"
-#include "mesh/display.h"
-#include "mesh/crypto.h"
-#include "mesh/net.h"
-#include "mesh/prov.h"
-
-#define PB_ADV_MTU 24
-
-#define DEFAULT_CONN_ID 0x00000000
-#define DEFAULT_PROV_MSG_NUM 0x00
-#define DEFAULT_DEV_MSG_NUM 0x80
-
-#define TX_TIMEOUT 30
-
-struct mesh_prov *mesh_prov_new(struct mesh_net *net, uint16_t remote)
-{
- struct mesh_prov *prov;
-
- prov = l_new(struct mesh_prov, 1);
-
- prov->remote = remote;
- prov->net = net;
-
- return mesh_prov_ref(prov);
-}
-
-struct mesh_prov *mesh_prov_ref(struct mesh_prov *prov)
-{
- if (!prov)
- return NULL;
-
- __sync_fetch_and_add(&prov->ref_count, 1);
-
- return prov;
-}
-
-void mesh_prov_unref(struct mesh_prov *prov)
-{
- struct mesh_io *io;
- uint8_t type;
-
- if (!prov)
- return;
-
- if (__sync_sub_and_fetch(&prov->ref_count, 1))
- return;
-
- io = mesh_net_get_io(prov->net);
- type = MESH_AD_TYPE_BEACON;
- mesh_io_send_cancel(io, &type, 1);
- type = MESH_AD_TYPE_PROVISION;
- mesh_io_send_cancel(io, &type, 1);
- mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_PROV);
- mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
- l_timeout_remove(prov->tx_timeout);
-
-
- l_info("Freed Prov Data");
- l_free(prov);
-}
-
-static void packet_received(struct mesh_prov *prov, const void *data,
- uint16_t size, uint8_t fcs)
-{
- if (prov->receive_callback)
- prov->receive_callback(data, size, prov);
-}
-
-static void send_open_req(struct mesh_prov *prov)
-{
- struct mesh_io *io;
- uint8_t open_req[23] = { MESH_AD_TYPE_PROVISION };
- struct mesh_io_send_info info = {
- .type = MESH_IO_TIMING_TYPE_GENERAL,
- .u.gen.interval = 50,
- .u.gen.cnt = 1,
- .u.gen.min_delay = 0,
- .u.gen.max_delay = 0,
- };
-
- if (!prov)
- return;
-
- io = mesh_net_get_io(prov->net);
- if (!io)
- return;
-
- l_put_be32(prov->conn_id, open_req + 1);
- open_req[1 + 4] = prov->local_msg_num = 0;
- open_req[1 + 4 + 1] = 0x03; /* OPEN_REQ */
- memcpy(open_req + 1 + 4 + 1 + 1, prov->uuid, 16);
-
- /* print_packet("PB-TX", open_req + 1, sizeof(open_req) - 1); */
- mesh_io_send_cancel(io, open_req, 1);
- mesh_io_send(io, &info, open_req, sizeof(open_req));
-}
-
-static void send_open_cfm(struct mesh_prov *prov)
-{
- struct mesh_io *io;
- uint8_t open_cfm[7] = { MESH_AD_TYPE_PROVISION };
- struct mesh_io_send_info info = {
- .type = MESH_IO_TIMING_TYPE_GENERAL,
- .u.gen.interval = 50,
- .u.gen.cnt = 1,
- .u.gen.min_delay = 0,
- .u.gen.max_delay = 0,
- };
-
- if (!prov)
- return;
-
- io = mesh_net_get_io(prov->net);
- if (!io)
- return;
-
- l_put_be32(prov->conn_id, open_cfm + 1);
- open_cfm[1 + 4] = 0;
- open_cfm[1 + 4 + 1] = 0x07; /* OPEN_CFM */
-
- /* print_packet("PB-TX", open_cfm + 1, sizeof(open_cfm) - 1); */
-
- mesh_io_send_cancel(io, open_cfm, 1);
- mesh_io_send(io, &info, open_cfm, sizeof(open_cfm));
-}
-
-static void send_close_ind(struct mesh_prov *prov, uint8_t reason)
-{
- uint8_t buf[8] = { MESH_AD_TYPE_PROVISION };
- struct mesh_io *io;
- struct mesh_io_send_info info = {
- .type = MESH_IO_TIMING_TYPE_GENERAL,
- .u.gen.interval = 50,
- .u.gen.cnt = 3,
- .u.gen.min_delay = 0,
- .u.gen.max_delay = 0,
- };
-
- if (!prov)
- return;
-
- if (prov->bearer == MESH_BEARER_ADV) {
- io = mesh_net_get_io(prov->net);
- if (!io)
- return;
-
- l_put_be32(prov->conn_id, buf + 1);
- buf[5] = 0;
- buf[6] = 0x0B; /* CLOSE_IND */
- buf[7] = reason;
-
- /* print_packet("PB-TX", buf + 1, sizeof(buf) - 1); */
-
- mesh_io_send_cancel(io, buf, 1);
- mesh_io_send(io, &info, buf, sizeof(buf));
- }
-
- prov->bearer = MESH_BEARER_IDLE;
-}
-
-static void tx_timeout(struct l_timeout *timeout, void *user_data)
-{
- struct mesh_prov *prov = user_data;
- uint8_t cancel[] = { MESH_AD_TYPE_PROVISION };
- struct mesh_io *io;
-
- if (!prov)
- return;
-
- l_timeout_remove(prov->tx_timeout);
- prov->tx_timeout = NULL;
-
- io = mesh_net_get_io(prov->net);
- if (!io)
- return;
-
- mesh_io_send_cancel(io, cancel, sizeof(cancel));
-
- l_info("TX timeout");
- mesh_prov_close(prov, 1);
-}
-
-static void send_adv_segs(struct mesh_prov *prov)
-{
- struct mesh_io *io = mesh_net_get_io(prov->net);
- struct mesh_io_send_info info = {
- .type = MESH_IO_TIMING_TYPE_GENERAL,
- .u.gen.interval = 50,
- .u.gen.cnt = MESH_IO_TX_COUNT_UNLIMITED,
- .u.gen.min_delay = 0,
- .u.gen.max_delay = 0,
- };
- const void *data = prov->packet_buf;
- uint16_t size = prov->packet_len;
- uint16_t init_size;
- uint8_t buf[1 + PB_ADV_MTU + 5] = { MESH_AD_TYPE_PROVISION };
- uint8_t max_seg;
- uint8_t consumed;
- int i;
-
- if (!size)
- return;
-
- mesh_io_send_cancel(io, buf, 1);
-
- l_put_be32(prov->conn_id, buf + 1);
- buf[1 + 4] = prov->local_msg_num;
-
- if (size > PB_ADV_MTU - 4) {
- max_seg = 1 +
- (((size - (PB_ADV_MTU - 4)) - 1) / (PB_ADV_MTU - 1));
- init_size = PB_ADV_MTU - 4;
- } else {
- max_seg = 0;
- init_size = size;
- }
-
- /* print_packet("FULL-TX", data, size); */
-
- l_debug("Sending %u fragments for %u octets", max_seg + 1, size);
-
- buf[1 + 4 + 1] = max_seg << 2;
- l_put_be16(size, buf + 1 + 4 + 1 + 1);
- buf[9] = mesh_crypto_compute_fcs(data, size);
- memcpy(buf + 1 + 4 + 1 + 1 + 2 + 1, data, init_size);
-
- l_debug("max_seg: %2.2x", max_seg);
- l_debug("size: %2.2x, CRC: %2.2x", size, buf[9]);
-
- /* print_packet("PB-TX", buf + 1, init_size + 9); */
- mesh_io_send(io, &info, buf, init_size + 10);
-
- consumed = init_size;
-
- for (i = 1; i <= max_seg; i++) {
- uint8_t seg_size; /* Amount of payload data being sent */
-
- if (size - consumed > PB_ADV_MTU - 1)
- seg_size = PB_ADV_MTU - 1;
- else
- seg_size = size - consumed;
-
- buf[6] = (i << 2) | 0x02;
- memcpy(buf + 7, data + consumed, seg_size);
-
- /* print_packet("PB-TX", buf + 1, seg_size + 6); */
-
- mesh_io_send(io, &info, buf, seg_size + 7);
-
- consumed += seg_size;
- }
-}
-
-static void send_adv_msg(struct mesh_prov *prov, const void *data,
- uint16_t size)
-{
- l_timeout_remove(prov->tx_timeout);
- prov->tx_timeout = l_timeout_create(TX_TIMEOUT, tx_timeout, prov, NULL);
-
- memcpy(prov->packet_buf, data, size);
- prov->packet_len = size;
-
- send_adv_segs(prov);
-}
-
-static void send_ack(struct mesh_prov *prov)
-{
- struct mesh_io *io = mesh_net_get_io(prov->net);
- struct mesh_io_send_info info = {
- .type = MESH_IO_TIMING_TYPE_GENERAL,
- .u.gen.interval = 50,
- .u.gen.cnt = 1,
- .u.gen.min_delay = 0,
- .u.gen.max_delay = 0,
- };
- uint8_t ack[7] = { MESH_AD_TYPE_PROVISION };
-
- l_put_be32(prov->conn_id, ack + 1);
- ack[1 + 4] = prov->last_peer_msg_num;
- ack[1 + 4 + 1] = 0x01; /* ACK */
-
- /* print_packet("ADV-ACK", ack + 1, sizeof(ack) - 1); */
- mesh_io_send(io, &info, ack, sizeof(ack));
-}
-
-static void adv_data_pkt(uint8_t type, const void *pkt, uint8_t size,
- void *user_data)
-{
- const uint8_t *data = pkt;
- struct mesh_prov *prov = user_data;
- uint16_t offset = 0;
-
- if ((type & 0x03) == 0x00) {
- uint8_t last_seg = type >> 2;
-
- prov->expected_len = l_get_be16(data);
- prov->expected_fcs = l_get_u8(data + 2);
-
- /* print_packet("Pkt", pkt, size); */
- data += 3;
- size -= 3;
-
- prov->trans = MESH_TRANS_RX;
-
- if (prov->expected_len > sizeof(prov->peer_buf)) {
- l_info("Incoming pkt exceeds storage %d > %ld",
- prov->expected_len, sizeof(prov->peer_buf));
- return;
- } else if (last_seg == 0)
- prov->trans = MESH_TRANS_IDLE;
-
- prov->expected_segs = 0xff >> (7 - last_seg);
- prov->got_segs |= 1;
- memcpy(prov->peer_buf, data, size);
-
- } else if ((type & 0x03) == 0x02) {
- offset = (PB_ADV_MTU - 4) + ((type >> 2) - 1) *
- (PB_ADV_MTU - 1);
-
- if (offset + size > prov->expected_len) {
- l_info("Incoming pkt exceeds agreed len %d + %d > %d",
- offset, size, prov->expected_len);
- return;
- }
-
- prov->trans = MESH_TRANS_RX;
-
- l_debug("Processing fragment %u", type & 0x3f);
-
- prov->got_segs |= 1 << (type >> 2);
- memcpy(prov->peer_buf + offset, data, size);
-
- } else if (type == 0x01) {
- if (prov->send_callback) {
- void *data = prov->send_data;
- mesh_prov_send_func_t cb = prov->send_callback;
-
- prov->trans = MESH_TRANS_IDLE;
- prov->send_callback = NULL;
- prov->send_data = NULL;
-
- cb(true, data);
- }
- return;
- } else
- return;
-
- if (prov->got_segs != prov->expected_segs)
- return;
-
- /* Validate RXed packet and pass up to Provisioning */
- if (!mesh_crypto_check_fcs(prov->peer_buf,
- prov->expected_len,
- prov->expected_fcs)) {
- l_debug("Invalid FCS");
- return;
- }
-
- prov->last_peer_msg_num = prov->peer_msg_num;
- send_ack(prov);
-
- prov->trans = MESH_TRANS_IDLE;
-
- packet_received(prov, prov->peer_buf,
- prov->expected_len, prov->expected_fcs);
-
- /* Reset Re-Assembly for next packet */
- prov->expected_len = sizeof(prov->peer_buf);
- prov->expected_fcs = 0;
- prov->expected_segs = 0;
- prov->got_segs = 0;
-
-}
-
-static void adv_bearer_packet(void *user_data, struct mesh_io_recv_info *info,
- const uint8_t *pkt, uint16_t len)
-{
- struct mesh_prov *prov = user_data;
- uint32_t conn_id;
- uint8_t msg_num;
- uint8_t type;
-
- if (len < 6) {
- l_info(" Too short packet");
- return;
- }
-
- conn_id = l_get_be32(pkt + 1);
- msg_num = l_get_u8(pkt + 1 + 4);
- type = l_get_u8(pkt + 1 + 4 + 1);
-
- /*if (prov->conn_id == conn_id) print_packet("ADV-RX", pkt, len); */
-
- if (prov->conn_id != DEFAULT_CONN_ID) {
- if (prov->conn_id != conn_id) {
- l_debug("rxed unknown conn_id: %8.8x != %8.8x",
- conn_id, prov->conn_id);
- return;
- }
- } else if (type != 0x03)
- return;
-
- /* print_packet("PB-ADV-RX", pkt, len); */
-
- /* Normalize pkt to start of PROV pkt payload */
- pkt += 7;
- len -= 7;
-
- if (type == 0x07) { /* OPEN_CFM */
- if (conn_id != prov->conn_id)
- return;
-
- if (msg_num != prov->local_msg_num)
- return;
-
- l_info("Link open confirmed");
-
- prov->bearer = MESH_BEARER_ADV;
- if (prov->open_callback)
- prov->open_callback(prov->receive_data);
- } else if (type == 0x01) {
- if (conn_id != prov->conn_id)
- return;
-
- if (msg_num != prov->local_msg_num)
- return;
-
- l_debug("Got ACK %d", msg_num);
- adv_data_pkt(type, pkt, len, user_data);
- } else if (type == 0x03) {
- /*
- * Ignore if:
- * 1. We are already provisioning
- * 2. We are not advertising that we are unprovisioned
- * 3. Open request not addressed to us
- */
- if (prov->conn_id != DEFAULT_CONN_ID &&
- prov->conn_id != conn_id)
- return;
-
- if (prov->local_msg_num != (DEFAULT_DEV_MSG_NUM - 1))
- return;
-
- if (memcmp(pkt, prov->uuid, 16))
- return;
-
- l_info("Link open request");
-
- prov->last_peer_msg_num = 0xFF;
- prov->bearer = MESH_BEARER_ADV;
- if (prov->open_callback && prov->conn_id == DEFAULT_CONN_ID)
- prov->open_callback(prov->receive_data);
-
- prov->conn_id = conn_id;
- prov->peer_msg_num = msg_num;
- send_open_cfm(prov);
- } else if (type == 0x0B) {
- if (prov->conn_id != conn_id)
- return;
-
- prov->conn_id = DEFAULT_CONN_ID;
- prov->local_msg_num = 0xFF;
- prov->peer_msg_num = 0xFF;
- prov->last_peer_msg_num = 0xFF;
-
- l_timeout_remove(prov->tx_timeout);
- prov->tx_timeout = NULL;
-
- l_info("Link closed notification: %2.2x", pkt[0]);
-
- if (prov->close_callback)
- prov->close_callback(prov->receive_data, pkt[0]);
- } else if ((type & 0x03) == 0x00) {
- if (prov->conn_id != conn_id)
- return;
-
- if (msg_num == prov->last_peer_msg_num) {
- send_ack(prov);
- return;
- }
-
- prov->peer_msg_num = msg_num;
-
- l_debug("Processing Data with %u fragments,%d octets",
- type >> 2, l_get_be16(pkt));
- adv_data_pkt(type, pkt, len, user_data);
-
- } else if ((type & 0x03) == 0x02) {
- if (prov->conn_id != conn_id)
- return;
-
- if (msg_num == prov->last_peer_msg_num) {
- send_ack(prov);
- return;
- }
-
- prov->peer_msg_num = msg_num;
-
- l_debug("Processing fragment %u", type >> 2);
- adv_data_pkt(type, pkt, len, user_data);
- }
-}
-
-static void beacon_packet(void *user_data, struct mesh_io_recv_info *info,
- const uint8_t *pkt, uint16_t len)
-{
- struct mesh_prov *prov = user_data;
- struct mesh_io *io;
-
- pkt++;
- len--;
-
- if (len < 19)
- return;
-
- if (!pkt[0])
- print_packet("UnProv-BEACON-RX", pkt, len);
-
- /* Ignore devices not matching UUID */
- if (pkt[0] || memcmp(pkt + 1, prov->uuid, 16))
- return;
-
- io = mesh_net_get_io(prov->net);
- mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
-
- if ((prov->conn_id != DEFAULT_CONN_ID) ||
- (prov->bearer != MESH_BEARER_IDLE)) {
- l_info("PB-ADV: Already Provisioning");
- return;
- }
-
- l_getrandom(&prov->conn_id, sizeof(prov->conn_id));
- prov->bearer = MESH_BEARER_ADV;
- send_open_req(prov);
-}
-
-static bool mesh_prov_enable(struct mesh_prov *prov, enum mesh_prov_mode mode,
- uint8_t uuid[16])
-{
- const uint8_t pb_adv_data[] = { MESH_AD_TYPE_BEACON, 0 };
- uint8_t adv_data[62];
- uint8_t adv_len, type;
- struct mesh_io *io;
- struct mesh_io_send_info tx_info = {
- .type = MESH_IO_TIMING_TYPE_GENERAL,
- .u.gen.interval = 1000, /* ms */
- .u.gen.cnt = 0, /* 0 == Infinite */
- .u.gen.min_delay = 0, /* no delay */
- .u.gen.max_delay = 0, /* no delay */
- };
-
- if (!prov || !prov->net)
- return false;
-
-
- prov->mode = mode;
- memcpy(prov->uuid, uuid, 16);
- prov->conn_id = DEFAULT_CONN_ID;
- io = mesh_net_get_io(prov->net);
-
- switch (mode) {
- case MESH_PROV_MODE_NONE:
- break;
- case MESH_PROV_MODE_INITIATOR:
- print_packet("Searching for uuid", uuid, 16);
- prov->local_msg_num = DEFAULT_PROV_MSG_NUM;
- prov->peer_msg_num = DEFAULT_DEV_MSG_NUM;
- mesh_io_register_recv_cb(io, MESH_IO_FILTER_PROV,
- adv_bearer_packet, prov);
- mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
- beacon_packet, prov);
- break;
-
- case MESH_PROV_MODE_ADV_ACCEPTOR:
- prov->local_msg_num = DEFAULT_DEV_MSG_NUM - 1;
- prov->peer_msg_num = DEFAULT_PROV_MSG_NUM;
-
- print_packet("Beaconing as unProvisioned uuid", uuid, 16);
- adv_len = sizeof(pb_adv_data);
- memcpy(adv_data, pb_adv_data, adv_len);
- memcpy(adv_data + adv_len, uuid, 16);
- adv_len += 16;
- adv_len += 2;
- mesh_io_register_recv_cb(io, MESH_IO_FILTER_PROV,
- adv_bearer_packet, prov);
- type = MESH_AD_TYPE_BEACON;
- mesh_io_send_cancel(io, &type, 1);
- mesh_io_send(io, &tx_info, adv_data, adv_len);
- break;
-
- case MESH_PROV_MODE_GATT_CLIENT:
- case MESH_PROV_MODE_MESH_GATT_CLIENT:
- case MESH_PROV_MODE_GATT_ACCEPTOR:
- case MESH_PROV_MODE_MESH_SERVER:
- case MESH_PROV_MODE_MESH_CLIENT:
- default:
- l_error("Unimplemented Prov Mode: %d", mode);
- break;
- }
-
- return true;
-}
-
-bool mesh_prov_listen(struct mesh_net *net, uint8_t uuid[16], uint8_t caps[12],
- mesh_prov_open_func_t open_callback,
- mesh_prov_close_func_t close_callback,
- mesh_prov_receive_func_t recv_callback,
- void *user_data)
-{
- struct mesh_prov *prov = mesh_net_get_prov(net);
-
- if (!prov) {
- prov = mesh_prov_new(net, 0);
- if (!prov)
- return false;
-
- mesh_net_set_prov(net, prov);
- }
-
- prov->open_callback = open_callback;
- prov->close_callback = close_callback;
- prov->receive_callback = recv_callback;
- prov->receive_data = prov; /* TODO: retink the callback placement */
- memcpy(prov->caps, caps, sizeof(prov->caps));
-
- prov->trans = MESH_TRANS_IDLE;
-
-
- return mesh_prov_enable(prov, MESH_PROV_MODE_ADV_ACCEPTOR, uuid);
-}
-
-unsigned int mesh_prov_send(struct mesh_prov *prov,
- const void *ptr, uint16_t size,
- mesh_prov_send_func_t send_callback,
- void *user_data)
-{
- const uint8_t *data = ptr;
-
- if (!prov)
- return 0;
-
- if (prov->trans != MESH_TRANS_IDLE)
- return 0;
-
- if (prov->remote) {
- /* TODO -- PB-Remote */
- } else {
- prov->send_callback = send_callback;
- prov->send_data = user_data;
- prov->trans = MESH_TRANS_TX;
- prov->local_msg_num++;
- send_adv_msg(prov, data, size);
- }
-
- return 1;
-}
-
-bool mesh_prov_close(struct mesh_prov *prov, uint8_t reason)
-{
- if (!prov)
- return false;
-
- prov->local_msg_num = 0;
- send_close_ind(prov, reason);
-
- prov->conn_id = DEFAULT_CONN_ID;
- prov->local_msg_num = 0xFF;
- prov->peer_msg_num = 0xFF;
- prov->last_peer_msg_num = 0xFF;
-
- if (prov->tx_timeout) {
- l_timeout_remove(prov->tx_timeout);
-
- /* If timing out, give Close indication 1 second of
- * provisioning timing to get final Close indication out
- */
- prov->tx_timeout = l_timeout_create(1, tx_timeout, prov, NULL);
- }
-
- if (prov->close_callback)
- prov->close_callback(prov->receive_data, reason);
-
- return false;
-}
-
-void mesh_prov_set_addr(struct mesh_prov *prov, uint16_t addr)
-{
- prov->addr = addr;
-}
-
-uint16_t mesh_prov_get_idx(struct mesh_prov *prov)
-{
- return prov->net_idx;
-}
diff --git a/mesh/provision.c b/mesh/provision.c
deleted file mode 100644
index 17422ce0a..000000000
--- a/mesh/provision.c
+++ /dev/null
@@ -1,1162 +0,0 @@
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2018 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/select.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <termios.h>
-
-#include <ctype.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <getopt.h>
-#include <time.h>
-#include <ell/ell.h>
-
-#include "mesh/mesh-defs.h"
-#include "src/shared/ecc.h"
-
-#include "mesh/display.h"
-#include "mesh/net_keys.h"
-#include "mesh/crypto.h"
-#include "mesh/net.h"
-#include "mesh/prov.h"
-#include "mesh/provision.h"
-#include "mesh/node.h"
-
-#define PROV_INVITE 0x00
-#define PROV_CAPS 0x01
-#define PROV_START 0x02
-#define PROV_PUB_KEY 0x03
-#define PROV_INP_CMPLT 0x04
-#define PROV_CONFIRM 0x05
-#define PROV_RANDOM 0x06
-#define PROV_DATA 0x07
-#define PROV_COMPLETE 0x08
-#define PROV_FAILED 0x09
-
-#define PROV_ERR_INVALID_PDU 0x01
-#define PROV_ERR_INVALID_FORMAT 0x02
-#define PROV_ERR_UNEXPECTED_PDU 0x03
-#define PROV_ERR_CONFIRM_FAILED 0x04
-#define PROV_ERR_INSUF_RESOURCE 0x05
-#define PROV_ERR_DECRYPT_FAILED 0x06
-#define PROV_ERR_UNEXPECTED_ERR 0x07
-#define PROV_ERR_CANT_ASSIGN_ADDR 0x08
-
-/* Expected Provisioning PDU sizes */
-static const uint16_t expected_pdu_size[] = {
- 1 + 1, /* PROV_INVITE */
- 1 + 1 + 2 + 1 + 1 + 1 + 2 + 1 + 2, /* PROV_CAPS */
- 1 + 1 + 1 + 1 + 1 + 1, /* PROV_START */
- 1 + 64, /* PROV_PUB_KEY */
- 1, /* PROV_INP_CMPLT */
- 1 + 16, /* PROV_CONFIRM */
- 1 + 16, /* PROV_RANDOM */
- 1 + 16 + 2 + 1 + 4 + 2 + 8, /* PROV_DATA */
- 1, /* PROV_COMPLETE */
- 1 + 1, /* PROV_FAILED */
-};
-
-static enum {
- PUB_KEY_TYPE_ephemeral,
- PUB_KEY_TYPE_available,
-} pub_key_type = PUB_KEY_TYPE_ephemeral;
-
-static enum {
- AUTH_TYPE_3a,
- AUTH_TYPE_3b,
- AUTH_TYPE_3c,
-} prov_auth_type = AUTH_TYPE_3c;
-
-enum {
- INT_PROV_IDLE,
- INT_PROV_INVITE_SENT,
- INT_PROV_INVITE_ACKED,
- INT_PROV_START_SENT,
- INT_PROV_START_ACKED,
- INT_PROV_KEY_SENT,
- INT_PROV_KEY_ACKED,
- INT_PROV_CONF_SENT,
- INT_PROV_CONF_ACKED,
- INT_PROV_RAND_SENT,
- INT_PROV_RAND_ACKED,
- INT_PROV_DATA_SENT,
- INT_PROV_DATA_ACKED,
-} int_prov_state = INT_PROV_IDLE;
-
-enum {
- ACP_PROV_IDLE,
- ACP_PROV_CAPS_SENT,
- ACP_PROV_CAPS_ACKED,
- ACP_PROV_KEY_SENT,
- ACP_PROV_KEY_ACKED,
- ACP_PROV_INP_CMPLT_SENT,
- ACP_PROV_INP_CMPLT_ACKED,
- ACP_PROV_CONF_SENT,
- ACP_PROV_CONF_ACKED,
- ACP_PROV_RAND_SENT,
- ACP_PROV_RAND_ACKED,
- ACP_PROV_CMPLT_SENT,
- ACP_PROV_FAIL_SENT,
-} acp_prov_state = ACP_PROV_IDLE;
-
-static uint8_t prov_expected;
-static int8_t prov_last = -1;
-
-static void int_prov_send_cmplt(bool success, struct mesh_prov *prov);
-static void acp_prov_send_cmplt(bool success, struct mesh_prov *prov);
-
-static void swap_u256_bytes(uint8_t *u256)
-{
- int i;
-
- /* End-to-End byte reflection of 32 octet buffer */
- for (i = 0; i < 16; i++) {
- u256[i] ^= u256[31 - i];
- u256[31 - i] ^= u256[i];
- u256[i] ^= u256[31 - i];
- }
-}
-
-static uint8_t u16_highest_bit(uint16_t mask)
-{
- uint8_t cnt = 0;
-
- if (!mask)
- return 0xff;
-
- while (mask & 0xfffe) {
- cnt++;
- mask >>= 1;
- }
-
- return cnt;
-}
-
-static void send_prov_start(struct mesh_prov *prov)
-{
- struct mesh_net *net = prov->net;
- struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
- uint8_t prov_start[6] = { PROV_START };
-
- memset(prov_start + 1, 0, 1 + 1 + 1 + 1 + 1);
- if (!(caps->algorithms & 0x0001)) {
- /* We only support FIPS P-256 Elliptic Curve */
- l_error("Unrecognized Algorithm %4.4x", caps->algorithms);
- return;
- }
-
- if (caps->pub_type) {
- /* Prov Step 2b: New device exposed PublicKey OOB */
- prov_start[2] = 0x01;
- pub_key_type = PUB_KEY_TYPE_available;
- } else {
- pub_key_type = PUB_KEY_TYPE_ephemeral;
- }
-
- if (caps->output_size &&
- caps->output_action) {
- /* Prov Step 3a: Output OOB used */
- prov_start[3] = 0x02;
- prov_start[4] = u16_highest_bit(caps->output_action);
- prov_start[5] = caps->output_size > 8 ?
- 8 : caps->output_size;
-
- prov_auth_type = AUTH_TYPE_3a;
-
- } else if (caps->input_size &&
- caps->input_action) {
- /* Prov Step 3b: Input OOB used */
- prov_start[3] = 0x03;
- prov_start[4] = u16_highest_bit(caps->input_action);
- prov_start[5] = caps->input_size > 8 ?
- 8 : caps->input_size;
-
- prov_auth_type = AUTH_TYPE_3b;
-
- } else {
- if (caps->static_type)
- prov_start[3] = 0x01;
-
- /* Prov Step 3c: Static OOB used (or no OOB available) */
- prov_auth_type = AUTH_TYPE_3c;
- }
-
- memcpy(&prov->conf_inputs.start, prov_start + 1,
- sizeof(prov->conf_inputs.start));
-
- int_prov_state = INT_PROV_START_SENT;
- if (pub_key_type == PUB_KEY_TYPE_ephemeral)
- prov_expected = PROV_PUB_KEY;
- else if (prov_auth_type == AUTH_TYPE_3b)
- prov_expected = PROV_INP_CMPLT;
- else
- prov_expected = PROV_CONFIRM;
-
- mesh_prov_send(prov, prov_start, 6,
- int_prov_send_cmplt, prov);
-
-}
-
-static void calculate_secrets(struct mesh_prov *prov, bool initiator)
-{
- struct mesh_net *net = prov->net;
- uint8_t *priv_key = mesh_net_priv_key_get(net);
- bool test_mode = mesh_net_test_mode(net);
- uint8_t tmp[64];
-
- if (initiator) {
- memcpy(prov->conf_inputs.prv_pub_key,
- prov->l_public, sizeof(prov->l_public));
- memcpy(prov->conf_inputs.dev_pub_key,
- prov->r_public, sizeof(prov->r_public));
- } else {
- memcpy(prov->conf_inputs.prv_pub_key,
- prov->r_public, sizeof(prov->r_public));
- memcpy(prov->conf_inputs.dev_pub_key,
- prov->l_public, sizeof(prov->l_public));
- }
-
- /* Convert to Mesh byte order */
- memcpy(tmp, prov->r_public, 64);
- swap_u256_bytes(tmp);
- swap_u256_bytes(tmp + 32);
-
- ecdh_shared_secret(tmp, priv_key, prov->secret);
-
- /* Convert to Mesh byte order */
- swap_u256_bytes(prov->secret);
-
- mesh_crypto_s1(&prov->conf_inputs,
- sizeof(prov->conf_inputs), prov->conf_salt);
-
-
- mesh_crypto_prov_conf_key(prov->secret, prov->conf_salt,
- prov->conf_key);
-
- if (test_mode) {
- print_packet("PublicKeyRemote", prov->r_public, 64);
- print_packet("PublicKeyLocal", prov->l_public, 64);
- print_packet("PrivateKeyLocal", priv_key, 32);
- print_packet("ConfirmationInputs", &prov->conf_inputs,
- sizeof(prov->conf_inputs));
- print_packet("ECDHSecret", prov->secret,
- sizeof(prov->secret));
- print_packet("ConfirmationSalt", prov->conf_salt, 16);
- print_packet("ConfirmationKey", prov->conf_key,
- sizeof(prov->conf_key));
- }
-}
-
-static void send_prov_key(struct mesh_prov *prov,
- mesh_prov_send_func_t send_callback)
-{
- uint8_t send_pub_key[65] = { PROV_PUB_KEY };
-
- memcpy(send_pub_key + 1, prov->l_public, 64);
- mesh_prov_send(prov, send_pub_key, 65,
- send_callback, prov);
-}
-
-static void send_prov_data(struct mesh_prov *prov)
-{
- struct mesh_net *net = prov->net;
- struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
- uint64_t mic;
- uint32_t iv_index;
- uint32_t net_key_id;
- uint8_t snb_flags;
- uint16_t net_idx = mesh_prov_get_idx(prov);
- uint8_t prov_data[1 + 16 + 2 + 1 + 4 + 2 + sizeof(mic)] = { PROV_DATA };
- uint16_t uni_addr = mesh_net_prov_uni(net, caps->num_ele);
- bool test_mode = mesh_net_test_mode(net);
-
- /* Calculate Provisioning Data */
- prov_expected = PROV_COMPLETE;
- mesh_net_get_snb_state(net, &snb_flags, &iv_index);
-
- mesh_net_get_key(net, !!(snb_flags & 0x01), net_idx, &net_key_id);
- net_key_retrieve(net_key_id, prov_data + 1);
- l_put_be16(net_idx, prov_data + 1 + 16);
- l_put_u8(snb_flags, prov_data + 1 + 16 + 2);
- l_put_be32(iv_index, prov_data + 1 + 16 + 2 + 1);
- l_put_be16(uni_addr, prov_data + 1 + 16 + 2 + 1 + 4);
-
- if (test_mode)
- print_packet("Data", prov_data + 1, 16 + 2 + 1 + 4 + 2);
-
- mesh_crypto_device_key(prov->secret, prov->prov_salt, prov->dev_key);
- if (test_mode) {
- print_packet("DevKey", prov->dev_key, 16);
- print_packet("NetworkKey", prov_data + 1, 16);
- print_packet("NetworkKey Index", prov_data + 1 + 16, 2);
- print_packet("SNB Flags", prov_data + 1 + 16 + 2, 1);
- print_packet("IVindex", prov_data + 1 + 16 + 2 + 1, 4);
- print_packet("Unicast Addr", prov_data + 1 + 16 + 2 + 1 + 4, 2);
- }
-
- mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
- NULL, 0,
- &prov_data[1],
- sizeof(prov_data) - 1 - sizeof(mic),
- &prov_data[1],
- &mic, sizeof(mic));
- if (test_mode)
- print_packet("DataEncrypted + mic", prov_data + 1,
- sizeof(prov_data) - 1);
-
- int_prov_state = INT_PROV_DATA_SENT;
- mesh_prov_send(prov, prov_data, sizeof(prov_data),
- int_prov_send_cmplt, prov);
- mesh_prov_set_addr(prov, uni_addr);
-}
-
-static void send_prov_conf(struct mesh_prov *prov,
- mesh_prov_send_func_t send_callback)
-{
- struct mesh_net *net = prov->net;
- uint8_t *test_rand = mesh_net_prov_rand(net);
- uint8_t prov_conf[1 + sizeof(prov->conf)] = { PROV_CONFIRM };
- bool test_mode = mesh_net_test_mode(net);
-
- if (test_mode && test_rand[0])
- memcpy(prov->rand_auth, test_rand, 16);
- else
- l_getrandom(prov->rand_auth, 16);
-
- /* Calculate Confirmation */
- mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
- sizeof(prov->rand_auth), prov->conf);
-
- /* Marshal Confirmation */
- memcpy(prov_conf + 1, prov->conf, sizeof(prov->conf));
-
- if (test_mode) {
- print_packet("ConfirmationKey", prov->conf_key,
- sizeof(prov->conf_key));
- print_packet("RandomAuthValue", prov->rand_auth,
- sizeof(prov->rand_auth));
- print_packet("Sending Confirmation", prov->conf,
- sizeof(prov->conf));
- }
-
- mesh_prov_send(prov, prov_conf, sizeof(prov_conf),
- send_callback, prov);
-}
-
-static void send_prov_rand(struct mesh_prov *prov,
- mesh_prov_send_func_t send_callback)
-{
- struct mesh_net *net = prov->net;
- uint8_t prov_rand[17] = { PROV_RANDOM };
- bool test_mode = mesh_net_test_mode(net);
-
- /* Marshal Random */
- memcpy(prov_rand + 1, prov->rand_auth, 16);
-
- if (test_mode)
- print_packet("Sending Random", prov->rand_auth, 16);
-
- mesh_prov_send(prov, prov_rand, sizeof(prov_rand),
- send_callback, prov);
-}
-
-enum inputType {
- INP_key,
- INP_dec,
- INP_text,
-};
-
-struct input_data {
- struct mesh_prov *prov;
- enum inputType type;
- bool initiator;
- void *dest;
- void *user_data;
- union {
- struct {
- uint8_t idx;
- char data[129];
- } key;
- struct {
- uint64_t value;
- } dec;
- struct {
- uint8_t idx;
- char str[16];
- } text;
- } u;
-};
-
-static void collectInput(struct mesh_prov *prov, char *prompt,
- enum inputType type, bool initiator,
- void *dest, void *user_data)
-{
- struct input_data *inp = l_new(struct input_data, 1);
-
- inp->prov = prov;
- inp->type = type;
- inp->dest = dest;
- inp->initiator = initiator;
- inp->user_data = user_data;
-
- if (prompt)
- l_info("%s", prompt);
-
- /* TODO: Request agent get OOB data */
-}
-
-static uint32_t digit_mod(uint8_t power)
-{
- uint32_t ret = 1;
-
- while (power--)
- ret *= 10;
-
- return ret;
-}
-
-static char *key_type(uint8_t type)
-{
- switch (type) {
- case 0x01:
- return "QR-Code";
- case 0x02:
- return "Barcode";
- case 0x03:
- return "NFC Tag";
- case 0x04:
- return "Printed Number";
- default:
- return "unknown Source";
- }
-}
-
-static void int_prov_send_cmplt(bool success, struct mesh_prov *prov)
-{
- struct mesh_net *net = prov->net;
- struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
-
- l_debug("Provision sending complete");
-
- switch (int_prov_state) {
- case INT_PROV_INVITE_SENT:
- int_prov_state = INT_PROV_INVITE_ACKED;
- if (acp_prov_state == ACP_PROV_CAPS_SENT)
- send_prov_start(prov);
- break;
- case INT_PROV_START_SENT:
- int_prov_state = INT_PROV_START_ACKED;
- if (pub_key_type == PUB_KEY_TYPE_ephemeral) {
- int_prov_state = INT_PROV_KEY_SENT;
- send_prov_key(prov, int_prov_send_cmplt);
- } else {
- collectInput(prov, NULL, INP_key, true,
- prov->r_public, prov);
- l_info("\n\nEnter key from %s:\n",
- key_type(caps->pub_type));
- }
- break;
- case INT_PROV_KEY_SENT:
- int_prov_state = INT_PROV_KEY_ACKED;
- if (pub_key_type == PUB_KEY_TYPE_ephemeral) {
- prov_expected = PROV_PUB_KEY;
- break;
- }
-
- /* Start Step 3 */
- memset(prov->rand_auth + 16, 0, 16);
- if (prov_auth_type == AUTH_TYPE_3a)
- collectInput(prov,
- "\n\nEnter prompted number from device:",
- INP_dec, true,
- prov->rand_auth + 32 - sizeof(uint32_t),
- prov);
-
- else if (prov_auth_type == AUTH_TYPE_3b) {
- uint32_t oob_key;
-
- l_getrandom(&oob_key, sizeof(uint32_t));
- oob_key %= digit_mod(caps->input_size);
- l_put_be32(oob_key,
- prov->rand_auth + 32 -
- sizeof(uint32_t));
- l_info("\n\nEnter %d on Device\n", oob_key);
- prov_expected = PROV_INP_CMPLT;
-
- } else if (caps->static_type) {
- collectInput(prov, NULL, INP_text, true,
- prov->rand_auth + 16, prov);
- l_info("\n\nstatic OOB str from %s:\n",
- key_type(caps->static_type));
-
- } else {
- int_prov_state = INT_PROV_CONF_SENT;
- send_prov_conf(prov, int_prov_send_cmplt);
- }
-
- break;
- case INT_PROV_CONF_SENT:
- int_prov_state = INT_PROV_CONF_ACKED;
- if (acp_prov_state == ACP_PROV_CONF_SENT) {
- int_prov_state = INT_PROV_RAND_SENT;
- prov_expected = PROV_RANDOM;
- send_prov_rand(prov, int_prov_send_cmplt);
- }
- break;
- case INT_PROV_RAND_SENT:
- int_prov_state = INT_PROV_RAND_ACKED;
- if (acp_prov_state == ACP_PROV_RAND_SENT)
- send_prov_data(prov);
- break;
- case INT_PROV_DATA_SENT:
- int_prov_state = INT_PROV_DATA_ACKED;
- break;
- default:
- case INT_PROV_INVITE_ACKED:
- case INT_PROV_START_ACKED:
- case INT_PROV_KEY_ACKED:
- case INT_PROV_CONF_ACKED:
- case INT_PROV_RAND_ACKED:
- case INT_PROV_DATA_ACKED:
- case INT_PROV_IDLE:
- break;
- }
-}
-
-void initiator_prov_open(struct mesh_prov *prov)
-{
- uint8_t invite[] = { PROV_INVITE, 30 };
- uint8_t *priv_key;
-
- l_info("Provisioning link opened");
-
- priv_key = mesh_net_priv_key_get(prov->net);
- ecc_make_key(prov->l_public, priv_key);
-
- int_prov_state = INT_PROV_INVITE_SENT;
- prov_expected = PROV_CAPS;
- prov_last = -1;
- prov->conf_inputs.invite.attention = invite[1];
- mesh_prov_send(prov, invite, sizeof(invite),
- int_prov_send_cmplt, prov);
-}
-
-void initiator_prov_close(struct mesh_prov *prov, uint8_t reason)
-{
- struct mesh_net *net = prov->net;
- uint32_t iv_index;
- uint8_t snb_flags;
-
- l_info("Provisioning link closed");
-
- /* Get the provisioned node's composition data*/
- if (reason == 0) {
- mesh_net_get_snb_state(net, &snb_flags, &iv_index);
-
- l_info("Save provisioner's DB");
- }
-}
-
-void initiator_prov_receive(const void *pkt, uint16_t size,
- struct mesh_prov *prov)
-{
- struct mesh_net *net = prov->net;
- struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
- bool test_mode = mesh_net_test_mode(net);
- const uint8_t *data = pkt;
- uint8_t tmp[16];
- uint8_t type = *data++;
- uint8_t err = 0;
-
-
- l_debug("Provisioning packet received type: %2.2x (%u octets)",
- type, size);
-
- if (type == prov_last) {
- l_error("Ignore repeated %2.2x packet", type);
- return;
- } else if ((type > prov_expected || type < prov_last) &&
- type != PROV_FAILED) {
- l_error("Expected %2.2x, Got:%2.2x", prov_expected, type);
- err = PROV_ERR_UNEXPECTED_PDU;
- goto failure;
- }
-
- if (type >= L_ARRAY_SIZE(expected_pdu_size) ||
- size != expected_pdu_size[type]) {
- l_error("Expected PDU size %d, Got %d (type: %2.2x)",
- expected_pdu_size[type], size, type);
- err = PROV_ERR_INVALID_FORMAT;
- goto failure;
- }
-
- prov_last = type;
-
- switch (type) {
- case PROV_CAPS: /* Capabilities */
- int_prov_state = INT_PROV_INVITE_ACKED;
- acp_prov_state = ACP_PROV_CAPS_SENT;
- caps->num_ele = data[0];
- if (test_mode)
- l_info("Got Num Ele %d", data[0]);
-
- caps->algorithms = l_get_be16(data + 1);
- if (test_mode)
- l_info("Got alg %d", caps->algorithms);
-
- caps->pub_type = data[3];
- if (test_mode)
- l_info("Got pub_type %d", data[3]);
-
- caps->static_type = data[4];
- if (test_mode)
- l_info("Got static_type %d", data[4]);
-
- caps->output_size = data[5];
- if (test_mode)
- l_info("Got output_size %d", data[5]);
-
- caps->output_action = l_get_be16(data + 6);
- if (test_mode)
- l_info("Got output_action %d", l_get_be16(data + 6));
-
- caps->input_size = data[8];
- if (test_mode)
- l_info("Got input_size %d", data[8]);
-
- caps->input_action = l_get_be16(data + 9);
- if (test_mode)
- l_info("Got input_action %d", l_get_be16(data + 9));
-
- if (caps->algorithms != 0x0001) {
- l_error("Unsupported Algorithm");
- err = PROV_ERR_INVALID_FORMAT;
- goto failure;
- }
-
- memcpy(&prov->conf_inputs.caps, data, 11);
-
- if (int_prov_state == INT_PROV_INVITE_ACKED)
- send_prov_start(prov);
- break;
-
- case PROV_PUB_KEY: /* Public Key */
- int_prov_state = INT_PROV_KEY_ACKED;
- acp_prov_state = ACP_PROV_KEY_SENT;
- memcpy(prov->r_public, data, 64);
- calculate_secrets(prov, true);
- prov_expected = PROV_CONFIRM;
-
- memset(prov->rand_auth + 16, 0, 16);
- if (prov_auth_type == AUTH_TYPE_3a) {
- collectInput(prov,
- "\n\nEnter number from device:",
- INP_dec, true,
- prov->rand_auth + 32 - sizeof(uint32_t),
- prov);
-
- } else if (prov_auth_type == AUTH_TYPE_3b) {
-
- uint32_t oob_key;
-
- l_getrandom(&oob_key, sizeof(uint32_t));
- oob_key %= digit_mod(caps->input_size);
- l_put_be32(oob_key,
- prov->rand_auth + 32 -
- sizeof(uint32_t));
- l_info("\n\nEnter %d on Device\n", oob_key);
- prov_expected = PROV_INP_CMPLT;
-
- } else if (caps->static_type) {
- collectInput(prov, NULL, INP_dec, true,
- prov->rand_auth + 16, prov);
- l_info("\n\nstatic OOB str from %s:\n",
- key_type(caps->static_type));
-
- } else
- send_prov_conf(prov, int_prov_send_cmplt);
- break;
-
- case PROV_INP_CMPLT: /* Provisioning Input Complete */
- acp_prov_state = ACP_PROV_INP_CMPLT_SENT;
- prov_expected = PROV_CONFIRM;
- send_prov_conf(prov, int_prov_send_cmplt);
- break;
-
- case PROV_CONFIRM: /* Confirmation */
- int_prov_state = INT_PROV_CONF_ACKED;
- acp_prov_state = ACP_PROV_CONF_SENT;
- /* RXed Device Confirmation */
- memcpy(prov->conf, data, sizeof(prov->conf));
- if (test_mode)
- print_packet("ConfirmationDevice", prov->conf,
- sizeof(prov->conf));
-
- if (int_prov_state == INT_PROV_CONF_ACKED) {
- prov_expected = PROV_RANDOM;
- send_prov_rand(prov, int_prov_send_cmplt);
- }
- break;
-
- case PROV_RANDOM: /* Random */
- int_prov_state = INT_PROV_RAND_ACKED;
- acp_prov_state = ACP_PROV_RAND_SENT;
-
- /* Calculate SessionKey while the data is fresh */
- mesh_crypto_prov_prov_salt(prov->conf_salt,
- prov->rand_auth, data,
- prov->prov_salt);
- mesh_crypto_session_key(prov->secret, prov->prov_salt,
- prov->s_key);
- mesh_crypto_nonce(prov->secret, prov->prov_salt, prov->s_nonce);
- if (test_mode) {
- print_packet("SessionKey", prov->s_key,
- sizeof(prov->s_key));
- print_packet("Nonce", prov->s_nonce,
- sizeof(prov->s_nonce));
- }
-
- /* RXed Device Confirmation */
- memcpy(prov->rand_auth, data, sizeof(prov->conf));
- if (test_mode)
- print_packet("RandomDevice", prov->rand_auth, 16);
-
- mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
- sizeof(prov->rand_auth), tmp);
-
- if (memcmp(tmp, prov->conf, sizeof(prov->conf))) {
- l_error("Provisioning Failed-Confirm compare)");
- err = PROV_ERR_CONFIRM_FAILED;
- goto failure;
- }
-
- if (int_prov_state == INT_PROV_RAND_ACKED) {
- prov_expected = PROV_COMPLETE;
- send_prov_data(prov);
- }
- break;
-
- case PROV_COMPLETE: /* Complete */
- l_info("Provisioning Complete");
- int_prov_state = INT_PROV_IDLE;
- mesh_prov_close(prov, 0);
- break;
-
- case PROV_FAILED: /* Failed */
- l_error("Provisioning Failed (reason: %d)", data[0]);
- err = data[0];
- goto failure;
-
- default:
- l_error("Unknown Pkt %2.2x", type);
- err = PROV_ERR_UNEXPECTED_PDU;
- goto failure;
- }
-
- return;
-
-failure:
- int_prov_state = INT_PROV_IDLE;
- mesh_prov_close(prov, err);
-}
-
-static void acp_prov_send_cmplt(bool success, struct mesh_prov *prov)
-{
- l_debug("Provision sending complete");
-
- switch (acp_prov_state) {
- case ACP_PROV_CAPS_SENT:
- acp_prov_state = ACP_PROV_CAPS_ACKED;
- if (int_prov_state == INT_PROV_KEY_SENT) {
- acp_prov_state = ACP_PROV_KEY_SENT;
- prov_expected = PROV_CONFIRM;
- send_prov_key(prov, acp_prov_send_cmplt);
- }
- break;
- case ACP_PROV_KEY_SENT:
- acp_prov_state = ACP_PROV_KEY_ACKED;
- if (int_prov_state == INT_PROV_CONF_SENT) {
- acp_prov_state = ACP_PROV_CONF_SENT;
- prov_expected = PROV_RANDOM;
- send_prov_conf(prov, acp_prov_send_cmplt);
- }
- break;
- case ACP_PROV_INP_CMPLT_SENT:
- acp_prov_state = ACP_PROV_INP_CMPLT_ACKED;
- break;
- case ACP_PROV_CONF_SENT:
- acp_prov_state = ACP_PROV_CONF_ACKED;
- if (int_prov_state == INT_PROV_RAND_SENT) {
- acp_prov_state = ACP_PROV_RAND_SENT;
- prov_expected = PROV_DATA;
- send_prov_rand(prov, acp_prov_send_cmplt);
- }
- break;
- case ACP_PROV_RAND_SENT:
- acp_prov_state = ACP_PROV_RAND_ACKED;
- break;
- case ACP_PROV_CMPLT_SENT:
- acp_prov_state = ACP_PROV_IDLE;
- mesh_net_provisioned_set(prov->net, true);
- default:
- case ACP_PROV_IDLE:
- case ACP_PROV_CAPS_ACKED:
- case ACP_PROV_KEY_ACKED:
- case ACP_PROV_INP_CMPLT_ACKED:
- case ACP_PROV_CONF_ACKED:
- case ACP_PROV_RAND_ACKED:
- case ACP_PROV_FAIL_SENT:
- break;
- }
-}
-
-void acceptor_prov_open(struct mesh_prov *prov)
-{
- uint8_t *priv_key;
-
- l_info("Provisioning link opened");
-
- priv_key = mesh_net_priv_key_get(prov->net);
- ecc_make_key(prov->l_public, priv_key);
-
- prov_expected = PROV_INVITE;
- prov_last = -1;
-}
-
-void acceptor_prov_close(struct mesh_prov *prov, uint8_t reason)
-{
- l_info("Provisioning link closed");
- mesh_prov_unref(prov);
-}
-
-static void prov_store_cfm(void *user_data, bool result)
-{
- struct mesh_prov *prov = user_data;
- uint8_t out[2];
-
- if (result) {
- acp_prov_state = ACP_PROV_CMPLT_SENT;
- out[0] = PROV_COMPLETE;
- mesh_prov_send(prov, out, 1,
- acp_prov_send_cmplt,
- prov);
- } else {
- acp_prov_state = ACP_PROV_FAIL_SENT;
- out[0] = PROV_FAILED;
- out[1] = PROV_ERR_INSUF_RESOURCE;
- mesh_prov_send(prov, out, 2, NULL, NULL);
- }
-}
-
-void acceptor_prov_receive(const void *pkt, uint16_t size,
- struct mesh_prov *prov)
-{
- struct mesh_net *net = prov->net;
- struct mesh_net_prov_caps *caps = mesh_net_prov_caps_get(net);
- uint8_t *priv_key = mesh_net_priv_key_get(net);
- bool test_mode = mesh_net_test_mode(net);
- bool ret;
- const uint8_t *data = pkt;
- uint8_t type = *data++;
- uint8_t out[129];
- uint8_t tmp[16];
- uint8_t rand_dev[16];
- uint64_t rx_mic, decode_mic;
-
- l_debug("Provisioning packet received type: %2.2x (%u octets)",
- type, size);
-
- if (type == prov_last) {
- l_error("Ignore repeated %2.2x packet", type);
- return;
- } else if (type > prov_expected || type < prov_last) {
- l_error("Expected %2.2x, Got:%2.2x", prov_expected, type);
- out[1] = PROV_ERR_UNEXPECTED_PDU;
- goto failure;
- }
-
- if (type >= L_ARRAY_SIZE(expected_pdu_size) ||
- size != expected_pdu_size[type]) {
- l_error("Expected PDU size %d, Got %d (type: %2.2x)",
- size, expected_pdu_size[type], type);
- out[1] = PROV_ERR_INVALID_FORMAT;
- goto failure;
- }
-
- prov_last = type;
-
- switch (type) {
- case PROV_INVITE: /* Prov Invite */
- int_prov_state = INT_PROV_INVITE_SENT;
- /* Prov Capabilities */
- out[0] = PROV_CAPS;
- out[1] = caps->num_ele;
- l_put_be16(caps->algorithms, out + 2);
- out[4] = caps->pub_type;
- out[5] = caps->static_type;
- out[6] = caps->output_size;
- l_put_be16(caps->output_action, out + 7);
- out[9] = caps->input_size;
- l_put_be16(caps->input_action, out + 10);
-
- prov->conf_inputs.invite.attention = data[0];
- memcpy(&prov->conf_inputs.caps, out + 1,
- sizeof(prov->conf_inputs.caps));
-
- acp_prov_state = ACP_PROV_CAPS_SENT;
- prov_expected = PROV_START;
- mesh_prov_send(prov, out, sizeof(*caps) + 1,
- acp_prov_send_cmplt, prov);
- break;
-
- case PROV_START: /* Prov Start */
- if (data[0]) {
- /* Only Algorithm 0x00 supported */
- l_error("Invalid Algorithm: %2.2x", data[0]);
- out[1] = PROV_ERR_INVALID_FORMAT;
- goto failure;
- }
-
- acp_prov_state = ACP_PROV_CAPS_ACKED;
- int_prov_state = INT_PROV_START_SENT;
- prov_expected = PROV_PUB_KEY;
- memcpy(&prov->conf_inputs.start, data,
- sizeof(prov->conf_inputs.start));
- if (data[1] == 1 && caps->pub_type) {
- pub_key_type = PUB_KEY_TYPE_available;
- ecc_make_key(prov->l_public, priv_key);
- } else if (data[1] == 0) {
- pub_key_type = PUB_KEY_TYPE_ephemeral;
- /* Use Ephemeral Key */
- l_getrandom(priv_key, 32);
- ecc_make_key(prov->l_public, priv_key);
- } else {
- out[1] = PROV_ERR_INVALID_FORMAT;
- goto failure;
- }
-
- swap_u256_bytes(prov->l_public);
- swap_u256_bytes(prov->l_public + 32);
-
- switch (data[2]) {
- default:
- out[1] = PROV_ERR_INVALID_FORMAT;
- goto failure;
-
- case 0x00:
- case 0x01:
- prov_auth_type = AUTH_TYPE_3c;
- break;
-
- case 0x02:
- prov_auth_type = AUTH_TYPE_3a;
- caps->output_action = 1 << data[3];
- caps->output_size = data[4];
- break;
-
- case 0x03:
- prov_auth_type = AUTH_TYPE_3b;
- caps->input_action = 1 << data[3];
- caps->input_size = data[4];
- break;
- }
- break;
-
- case PROV_PUB_KEY: /* Public Key */
- int_prov_state = INT_PROV_KEY_SENT;
- prov_expected = PROV_CONFIRM;
- /* Save Key */
- memcpy(prov->r_public, data, 64);
- calculate_secrets(prov, false);
-
- if (pub_key_type == PUB_KEY_TYPE_ephemeral) {
- acp_prov_state = ACP_PROV_KEY_SENT;
- send_prov_key(prov, acp_prov_send_cmplt);
- }
-
- /* Start Step 3 */
- memset(prov->rand_auth + 16, 0, 16);
- if (prov_auth_type == AUTH_TYPE_3a) {
- uint32_t oob_key;
-
- l_getrandom(&oob_key, sizeof(uint32_t));
- oob_key %= digit_mod(caps->output_size);
- l_put_be32(oob_key,
- prov->rand_auth + 32 - sizeof(uint32_t));
- l_info("\n\nEnter %d on Provisioner\n",
- oob_key);
-
- } else if (prov_auth_type == AUTH_TYPE_3b) {
- if (caps->input_action == (1 << 3)) {
- /* TODO: Collect Text Input data */
- ;
- } else {
- /* TODO: Collect Decimal Input data */
- ;
- }
-
- } else {
- if (caps->static_type) {
- /* TODO: Collect Static Input data */
- /* (If needed) */
- ;
- }
- }
-
- break;
-
- case PROV_CONFIRM: /* Confirmation */
- int_prov_state = INT_PROV_CONF_SENT;
- acp_prov_state = ACP_PROV_KEY_ACKED;
- /* RXed Provision Confirmation */
- memcpy(prov->r_conf, data, sizeof(prov->r_conf));
- if (test_mode)
- print_packet("ConfirmationProvisioner",
- prov->r_conf,
- sizeof(prov->r_conf));
-
- if (acp_prov_state == ACP_PROV_KEY_ACKED) {
- prov_expected = PROV_RANDOM;
- send_prov_conf(prov, acp_prov_send_cmplt);
- }
- break;
-
- case PROV_RANDOM: /* Random */
- int_prov_state = INT_PROV_RAND_SENT;
- acp_prov_state = ACP_PROV_CONF_ACKED;
-
- /* Calculate Session key while the data is fresh */
- mesh_crypto_prov_prov_salt(prov->conf_salt, data,
- prov->rand_auth,
- prov->prov_salt);
- mesh_crypto_session_key(prov->secret, prov->prov_salt,
- prov->s_key);
- mesh_crypto_nonce(prov->secret, prov->prov_salt, prov->s_nonce);
-
- if (test_mode) {
- print_packet("SessionKey", prov->s_key,
- sizeof(prov->s_key));
- print_packet("Nonce", prov->s_nonce,
- sizeof(prov->s_nonce));
- }
-
-
- /* Save Local Random data to send after verification */
- memcpy(rand_dev, prov->rand_auth, 16);
- /* RXed Provisioner Confirmation */
- memcpy(prov->rand_auth, data, 16);
- if (test_mode)
- print_packet("RandomProvisioner", prov->rand_auth, 16);
-
- mesh_crypto_aes_cmac(prov->conf_key, prov->rand_auth,
- sizeof(prov->rand_auth), tmp);
-
- if (memcmp(tmp, prov->r_conf,
- sizeof(prov->r_conf))) {
- l_error("Provisioning Failed-Confirm compare");
- out[1] = PROV_ERR_CONFIRM_FAILED;
- goto failure;
- }
-
-
- memcpy(prov->rand_auth, rand_dev, 16);
- if (acp_prov_state == ACP_PROV_CONF_ACKED) {
- prov_expected = PROV_DATA;
- send_prov_rand(prov, acp_prov_send_cmplt);
- }
- break;
-
- case PROV_DATA: /* Provisioning Data */
- int_prov_state = INT_PROV_DATA_SENT;
- acp_prov_state = ACP_PROV_RAND_ACKED;
- if (test_mode) {
- print_packet("DataEncrypted + mic", data, size - 1);
- print_packet("Rxed-mic", data + 16 + 2 + 1 + 4 + 2, 8);
- }
-
- rx_mic = l_get_be64(data + 16 + 2 + 1 + 4 + 2);
- mesh_crypto_aes_ccm_decrypt(prov->s_nonce, prov->s_key,
- NULL, 0,
- data, size - 1, out + 1,
- &decode_mic, sizeof(decode_mic));
-
- if (test_mode) {
- print_packet("Data", out + 1, 16 + 2 + 1 + 4 + 2);
- l_info("Calc-mic: %16.16lx", decode_mic);
- }
-
- if (rx_mic == decode_mic) {
- mesh_crypto_device_key(prov->secret,
- prov->prov_salt,
- prov->dev_key);
- if (test_mode) {
- print_packet("DevKey", prov->dev_key, 16);
- print_packet("NetworkKey", out + 1, 16);
- print_packet("NetworkKey Index",
- out + 1 + 16, 2);
- print_packet("SNB Flags",
- out + 1 + 16 + 2, 1);
- print_packet("IVindex",
- out + 1 + 16 + 2 + 1, 4);
- print_packet("Unicast Addr",
- out + 1 + 16 + 2 + 1 + 4, 2);
- }
-
- /* Set Provisioned Data */
- ret = mesh_net_provisioned_new(prov->net,
- prov->dev_key,
- l_get_be16(out + 17),
- out + 1,
- l_get_be16(out + 24),
- out[19],
- l_get_be32(out + 20),
- prov_store_cfm, prov);
-
- if (!ret) {
- out[1] = PROV_ERR_INSUF_RESOURCE;
- goto failure;
- }
- } else {
- l_error("Provisioning Failed-MIC compare");
- out[1] = PROV_ERR_DECRYPT_FAILED;
- goto failure;
- }
- break;
-
- default:
- l_error("Unknown Pkt %2.2x", type);
- out[1] = PROV_ERR_UNEXPECTED_PDU;
- goto failure;
- }
-
- return;
-
-failure:
- acp_prov_state = ACP_PROV_FAIL_SENT;
- out[0] = PROV_FAILED;
- mesh_prov_send(prov, out, 2, acp_prov_send_cmplt, prov);
-}
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 03/30] mesh: Utilities for DBus support
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 02/30] mesh: Delete obsolete files Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 04/30] mesh: Internal errors Brian Gix
` (26 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/dbus.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mesh/dbus.h | 40 ++++++++++++++
2 files changed, 221 insertions(+)
create mode 100644 mesh/dbus.c
create mode 100644 mesh/dbus.h
diff --git a/mesh/dbus.c b/mesh/dbus.c
new file mode 100644
index 000000000..a8b398f9e
--- /dev/null
+++ b/mesh/dbus.c
@@ -0,0 +1,181 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2018 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 <time.h>
+#include <ell/ell.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
+#include "src/shared/mgmt.h"
+
+#include "mesh/mesh-defs.h"
+#include "mesh/mesh-io.h"
+#include "mesh/node.h"
+#include "mesh/net.h"
+#include "mesh/storage.h"
+#include "mesh/cfgmod.h"
+#include "mesh/model.h"
+#include "mesh/mesh.h"
+#include "mesh/error.h"
+#include "mesh/dbus.h"
+
+struct l_dbus *dbus;
+
+struct error_entry {
+ const char *dbus_err;
+ const char *default_desc;
+};
+
+/*
+ * Important: The entries in this table are ordered to enum
+ * values in mesh_error_t (error.h)
+ */
+static struct error_entry error_table[] =
+{
+ { NULL, NULL },
+ { ERROR_INTERFACE ".Failed", "Operation failed" },
+ { ERROR_INTERFACE ".NotAuthorized", "Permission denied"},
+ { ERROR_INTERFACE ".NotFound", "Object not found"},
+ { ERROR_INTERFACE ".InvalidArgs", "Invalid arguments"},
+ { ERROR_INTERFACE ".InProgress", "Already in progress"},
+ { ERROR_INTERFACE ".AlreadyExists", "Already exists"},
+ { ERROR_INTERFACE ".DoesNotExist", "Does not exist"},
+ { ERROR_INTERFACE ".Canceled", "Operation canceled"}
+};
+
+struct l_dbus_message *dbus_error(struct l_dbus_message *msg, int err,
+ const char *description)
+{
+ int array_len = L_ARRAY_SIZE(error_table);
+
+ /* Default to ".Failed" */
+ if (!err || err >= array_len)
+ err = MESH_ERROR_FAILED;
+
+ if (description)
+ return l_dbus_message_new_error(msg,
+ error_table[err].dbus_err,
+ "%s", description);
+ else
+ return l_dbus_message_new_error(msg,
+ error_table[err].dbus_err,
+ "%s", error_table[err].default_desc);
+}
+
+struct l_dbus *dbus_get_bus(void)
+{
+ return dbus;
+}
+
+uint32_t dbus_get_byte_array(struct l_dbus_message_iter *array, uint8_t *buf,
+ uint32_t max_len)
+{
+ uint32_t i;
+
+ for (i = 0; i < max_len; i++) {
+ if (!l_dbus_message_iter_next_entry(array, buf + i))
+ break;
+ }
+
+ return i;
+}
+
+uint32_t dbus_disconnect_watch_add(struct l_dbus *dbus, const char *name,
+ l_dbus_watch_func_t callback,
+ void *user_data)
+{
+ return l_dbus_add_signal_watch(dbus, "org.freedesktop.DBus",
+ "/org/freedesktop/DBus",
+ L_DBUS_INTERFACE_DBUS, "NameOwnerChanged",
+ L_DBUS_MATCH_ARGUMENT(0), name,
+ L_DBUS_MATCH_NONE,
+ callback, user_data);
+}
+
+bool dbus_disconnect_watch_remove(struct l_dbus *dbus, uint32_t id)
+{
+ return l_dbus_remove_signal_watch(dbus, id);
+}
+
+bool dbus_init(struct l_dbus *bus)
+{
+ /* Network interface */
+ if (!mesh_dbus_init(bus))
+ return false;
+
+ /* Node interface */
+ if (!node_dbus_init(bus))
+ return false;
+
+ dbus = bus;
+
+ return true;
+}
+
+bool dbus_match_interface(struct l_dbus_message_iter *interfaces,
+ const char *match)
+{
+ const char *interface;
+ struct l_dbus_message_iter properties;
+
+ while (l_dbus_message_iter_next_entry(interfaces, &interface,
+ &properties)) {
+ if (!strcmp(match, interface))
+ return true;
+ }
+
+ return false;
+}
+
+bool dbus_append_byte_array(struct l_dbus_message_builder *builder,
+ const uint8_t *data, int len)
+{
+ int i;
+
+ if (!l_dbus_message_builder_enter_array(builder, "y"))
+ return false;
+
+ for (i = 0; i < len; i++)
+ if (!l_dbus_message_builder_append_basic(builder, 'y',
+ data + i))
+ return false;
+
+ if (!l_dbus_message_builder_leave_array(builder))
+ return false;
+
+ return true;
+}
+
+void dbus_append_dict_entry_basic(struct l_dbus_message_builder *builder,
+ const char *key, const char *signature,
+ const void *data)
+{
+ 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);
+}
diff --git a/mesh/dbus.h b/mesh/dbus.h
new file mode 100644
index 000000000..90cbe9e5c
--- /dev/null
+++ b/mesh/dbus.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2018 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 BLUEZ_MESH_PATH "/org/bluez/mesh"
+#define BLUEZ_MESH_SERVICE "org.bluez.mesh"
+
+bool dbus_init(struct l_dbus *dbus);
+struct l_dbus *dbus_get_bus(void);
+uint32_t dbus_disconnect_watch_add(struct l_dbus *dbus, const char *name,
+ l_dbus_watch_func_t callback,
+ void *user_data);
+bool dbus_disconnect_watch_remove(struct l_dbus *dbus, uint32_t id);
+uint32_t dbus_get_byte_array(struct l_dbus_message_iter *array, uint8_t *buf,
+ uint32_t max_len);
+bool dbus_append_byte_array(struct l_dbus_message_builder *builder,
+ const uint8_t *data, int len);
+void dbus_append_dict_entry_basic(struct l_dbus_message_builder *builder,
+ const char *key, const char *signature,
+ const void *data);
+bool dbus_match_interface(struct l_dbus_message_iter *interfaces,
+ const char *match);
+struct l_dbus_message *dbus_error(struct l_dbus_message *msg, int err,
+ const char *description);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 04/30] mesh: Internal errors
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (2 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 03/30] mesh: Utilities for DBus support Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 05/30] mesh: Re-write storage for Multiple Nodes Brian Gix
` (25 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/error.h | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 mesh/error.h
diff --git a/mesh/error.h b/mesh/error.h
new file mode 100644
index 000000000..e7bac445b
--- /dev/null
+++ b/mesh/error.h
@@ -0,0 +1,35 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2018 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.
+ *
+ *
+ */
+
+/*
+ * Important: Changes in this table must be reflected in the
+ * the entries of error_table[] in dbus.c
+ */
+typedef enum {
+ MESH_ERROR_NONE,
+ MESH_ERROR_FAILED,
+ MESH_ERROR_NOT_AUTHORIZED,
+ MESH_ERROR_NOT_FOUND,
+ MESH_ERROR_INVALID_ARGS,
+ MESH_ERROR_BUSY,
+ MESH_ERROR_ALREADY_EXISTS,
+ MESH_ERROR_DOES_NOT_EXIST,
+ MESH_ERROR_CANCELED,
+} mesh_error_t;
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 05/30] mesh: Re-write storage for Multiple Nodes
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (3 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 04/30] mesh: Internal errors Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 06/30] mesh: Rewrite Node handling for multiple nodes Brian Gix
` (24 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/storage.c | 574 +++++++++++++++++++++++++--------------------------------
mesh/storage.h | 39 ++--
2 files changed, 273 insertions(+), 340 deletions(-)
diff --git a/mesh/storage.c b/mesh/storage.c
index 1f3b25886..fa96af05c 100644
--- a/mesh/storage.c
+++ b/mesh/storage.c
@@ -27,6 +27,8 @@
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
+#include <dirent.h>
+#include <libgen.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -42,39 +44,43 @@
#include "mesh/net.h"
#include "mesh/appkey.h"
#include "mesh/model.h"
+#include "mesh/mesh-db.h"
#include "mesh/storage.h"
-/*
- * TODO: figure out naming convention to store alternative nodes
- * Mesh storage dir wil be in configure.ac
- */
-#define DEVICE_COMPOSITION_FILE "../config/composition.json"
-#define NODE_CONGIGURATION_FILE "../config/configuration.json"
+struct write_info {
+ json_object *jnode;
+ const char *config_name;
+ void *user_data;
+ mesh_status_func_t cb;
+};
-static bool read_local_node_cb(struct mesh_db_node *db_node, void *user_data)
+static const char *storage_dir;
+static struct l_queue *node_ids;
+
+static bool simple_match(const void *a, const void *b)
{
- struct mesh_net *net = user_data;
- struct mesh_node *node;
+ return a == b;
+}
+
+static bool read_node_cb(struct mesh_db_node *db_node, void *user_data)
+{
+ struct mesh_node *node = user_data;
+ struct mesh_net *net;
uint32_t seq_number;
- uint16_t crpl;
uint8_t ttl, mode, cnt, num_ele;
uint16_t unicast, interval;
uint8_t *uuid;
- if (!net)
- return false;
-
- node = node_create_from_storage(net, db_node, true);
- if (!node)
+ if (!node_init_from_storage(node, db_node)) {
+ node_free(node);
return false;
+ }
- mesh_net_local_node_set(net, node, db_node->provisioner);
+ net = node_get_net(node);
seq_number = node_get_sequence_number(node);
mesh_net_set_seq_num(net, seq_number);
ttl = node_default_ttl_get(node);
mesh_net_set_default_ttl(net, ttl);
- crpl = node_get_crpl(node);
- mesh_net_set_crpl(net, crpl);
mode = node_proxy_mode_get(node);
if (mode == MESH_MODE_ENABLED || mode == MESH_MODE_DISABLED)
@@ -103,6 +109,7 @@ static bool read_local_node_cb(struct mesh_db_node *db_node, void *user_data)
uuid = node_uuid_get(node);
if (uuid)
mesh_net_id_uuid_set(net, uuid);
+
return true;
}
@@ -132,13 +139,14 @@ static bool read_app_keys_cb(uint16_t net_idx, uint16_t app_idx, uint8_t *key,
return appkey_key_init(net, net_idx, app_idx, key, new_key);
}
-static bool parse_local_node(struct mesh_net *net, json_object *jnode)
+static bool parse_node(struct mesh_node *node, json_object *jnode)
{
bool bvalue;
uint32_t iv_index;
uint8_t key_buf[16];
uint8_t cnt;
uint16_t interval;
+ struct mesh_net *net = node_get_net(node);
if (mesh_db_read_iv_index(jnode, &iv_index, &bvalue))
mesh_net_set_iv_index(net, iv_index, bvalue);
@@ -147,97 +155,35 @@ static bool parse_local_node(struct mesh_net *net, json_object *jnode)
mesh_net_transmit_params_set(net, cnt, interval);
/* Node composition/configuration info */
- if (!mesh_db_read_node(jnode, read_local_node_cb, net))
+ if (!mesh_db_read_node(jnode, read_node_cb, node))
return false;
if (!mesh_db_read_net_keys(jnode, read_net_keys_cb, net))
return false;
- /* TODO: use the actual "primary" network index for this node */
- if (mesh_db_read_device_key(jnode, key_buf) &&
- !node_set_device_key(mesh_net_local_node_get(net), key_buf))
+ if (!mesh_db_read_device_key(jnode, key_buf))
return false;
- mesh_db_read_app_keys(jnode, read_app_keys_cb, net);
-
- return true;
-}
-
-static bool read_unprov_device_cb(struct mesh_db_node *db_node, void *user_data)
-{
- struct mesh_net *net = user_data;
- struct mesh_node *node;
- uint16_t crpl;
- uint8_t *uuid;
-
- if (!net)
- return false;
+ node_set_device_key(node, key_buf);
- node = node_create_from_storage(net, db_node, true);
-
- if (!node)
- return false;
-
- mesh_net_local_node_set(net, node, db_node->provisioner);
- crpl = node_get_crpl(node);
- mesh_net_set_crpl(net, crpl);
-
- uuid = node_uuid_get(node);
- if (uuid)
- mesh_net_id_uuid_set(net, uuid);
+ mesh_db_read_app_keys(jnode, read_app_keys_cb, net);
return true;
}
-static bool parse_unprovisioned_device(struct mesh_net *net, json_object *jnode)
-{
- struct mesh_db_prov prov;
- struct mesh_net_prov_caps *caps;
- struct mesh_node *node;
-
- /* Node composition/configuration info */
- if (!mesh_db_read_unprovisioned_device(jnode,
- read_unprov_device_cb, net))
- return false;
-
- if (!mesh_db_read_prov_info(jnode, &prov))
- return false;
-
- caps = mesh_net_prov_caps_get(net);
- if (!caps)
- return false;
-
- node = mesh_net_local_node_get(net);
- if (!node)
- return false;
-
- caps->num_ele = node_get_num_elements(node);
- l_put_le16(prov.algorithm, &caps->algorithms);
- caps->pub_type = prov.pub_type;
- caps->static_type = prov.static_type;
- caps->output_size = prov.output_oob.size;
- l_put_le16(prov.output_oob.actions, &caps->output_action);
- caps->input_size = prov.input_oob.size;
- l_put_le16(prov.input_oob.actions, &caps->input_action);
-
- return mesh_net_priv_key_set(net, prov.priv_key);
-}
-
-static bool parse_config(struct mesh_net *net, const char *config_name,
- bool unprovisioned)
+static bool parse_config(char *in_file, char *out_file, uint16_t node_id)
{
int fd;
char *str;
- const char *out;
struct stat st;
ssize_t sz;
json_object *jnode = NULL;
bool result = false;
+ struct mesh_node *node;
- if (!config_name)
- return false;
+ l_info("Loading configuration from %s", in_file);
- fd = open(config_name, O_RDONLY);
+ fd = open(in_file, O_RDONLY);
if (!fd)
return false;
@@ -254,7 +200,7 @@ static bool parse_config(struct mesh_net *net, const char *config_name,
sz = read(fd, str, st.st_size);
if (sz != st.st_size) {
- l_error("Failed to read configuration file");
+ l_error("Failed to read configuration file %s", in_file);
goto done;
}
@@ -262,22 +208,19 @@ static bool parse_config(struct mesh_net *net, const char *config_name,
if (!jnode)
goto done;
- mesh_net_jconfig_set(net, jnode);
+ node = node_new();
- if (!unprovisioned)
- result = parse_local_node(net, jnode);
- else
- result = parse_unprovisioned_device(net, jnode);
+ node_jconfig_set(node, jnode);
+ node_cfg_file_set(node, out_file);
+ node_id_set(node, node_id);
+
+ result = parse_node(node, jnode);
if (!result) {
- storage_release(net);
- goto done;
+ json_object_put(jnode);
+ node_free(node);
}
- mesh_net_cfg_file_get(net, &out);
- if (!out)
- mesh_net_cfg_file_set(net, !unprovisioned ?
- config_name : NODE_CONGIGURATION_FILE);
done:
close(fd);
if (str)
@@ -286,166 +229,70 @@ done:
return result;
}
-bool storage_parse_config(struct mesh_net *net, const char *config_name)
-{
- bool result = false;
- bool unprovisioned = !config_name;
-
- if (unprovisioned) {
- result = parse_config(net, DEVICE_COMPOSITION_FILE, true);
- goto done;
- }
-
- result = parse_config(net, config_name, false);
-
- if (!result) {
- size_t len = strlen(config_name) + 5;
- char *bak = l_malloc(len);
-
- /* Fall-back to Backup version */
- strncpy(bak, config_name, len);
- bak = strncat(bak, ".bak", 5);
-
- remove(config_name);
- rename(bak, config_name);
-
- result = parse_config(net, config_name, false);
-
- l_free(bak);
- }
-
- /* If configuration read fails, try as unprovisioned device */
- if (!result) {
- l_info("Parse configuration failed, trying unprovisioned");
- unprovisioned = true;
- result = parse_config(net, DEVICE_COMPOSITION_FILE, true);
- }
-
-done:
- if (result)
- mesh_net_provisioned_set(net, !unprovisioned);
-
- return result;
-}
-
-bool storage_local_set_ttl(struct mesh_net *net, uint8_t ttl)
+bool storage_set_ttl(json_object *jnode, uint8_t ttl)
{
- json_object *jnode;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
return mesh_db_write_int(jnode, "defaultTTL", ttl);
}
-bool storage_local_set_relay(struct mesh_net *net, bool enable,
+bool storage_set_relay(json_object *jnode, bool enable,
uint8_t count, uint8_t interval)
{
- json_object *jnode;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
return mesh_db_write_relay_mode(jnode, enable, count, interval);
}
-bool storage_local_set_transmit_params(struct mesh_net *net, uint8_t count,
+bool storage_set_transmit_params(json_object *jnode, uint8_t count,
uint8_t interval)
{
- json_object *jnode;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
return mesh_db_write_net_transmit(jnode, count, interval);
}
-bool storage_local_set_mode(struct mesh_net *net, uint8_t mode,
+bool storage_set_mode(json_object *jnode, uint8_t mode,
const char *mode_name)
{
- json_object *jnode;
-
- if (!net || !mode_name)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
return mesh_db_write_mode(jnode, mode_name, mode);
}
-bool storage_model_bind(struct mesh_net *net, uint16_t addr, uint32_t mod_id,
+bool storage_model_bind(struct mesh_node *node, uint16_t addr, uint32_t mod_id,
uint16_t app_idx, bool unbind)
{
json_object *jnode;
- bool is_local;
+ int ele_idx;
+ bool is_vendor = (mod_id > 0xffff);
- if (!net)
+ ele_idx = node_get_element_idx(node, addr);
+ if (ele_idx < 0)
return false;
- is_local = mesh_net_is_local_address(net, addr);
- if (is_local) {
- int ele_idx;
- bool is_vendor = (mod_id > 0xffff);
-
- ele_idx = node_get_element_idx(mesh_net_local_node_get(net),
- addr);
- if (ele_idx < 0)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
- if (unbind)
- return mesh_db_model_binding_del(jnode, ele_idx,
- is_vendor, mod_id, app_idx);
- else
- return mesh_db_model_binding_add(jnode, ele_idx,
- is_vendor, mod_id, app_idx);
- }
+ jnode = node_jconfig_get(node);
- /* TODO: write remote node bindings to provisioner DB */
- return false;
+ if (unbind)
+ return mesh_db_model_binding_del(jnode, ele_idx, is_vendor,
+ mod_id, app_idx);
+ else
+ return mesh_db_model_binding_add(jnode, ele_idx, is_vendor,
+ mod_id, app_idx);
}
-bool storage_local_app_key_add(struct mesh_net *net, uint16_t net_idx,
+bool storage_app_key_add(struct mesh_net *net, uint16_t net_idx,
uint16_t app_idx, const uint8_t key[16], bool update)
{
json_object *jnode;
+ struct mesh_node *node = mesh_net_node_get(net);
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
+ jnode = node_jconfig_get(node);
if (!jnode)
return false;
return mesh_db_app_key_add(jnode, net_idx, app_idx, key, update);
}
-bool storage_local_app_key_del(struct mesh_net *net, uint16_t net_idx,
+bool storage_app_key_del(struct mesh_net *net, uint16_t net_idx,
uint16_t app_idx)
{
json_object *jnode;
+ struct mesh_node *node = mesh_net_node_get(net);
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
+ jnode = node_jconfig_get(node);
if (!jnode)
return false;
@@ -453,116 +300,53 @@ bool storage_local_app_key_del(struct mesh_net *net, uint16_t net_idx,
}
-bool storage_local_net_key_add(struct mesh_net *net, uint16_t net_idx,
+bool storage_net_key_add(struct mesh_net *net, uint16_t net_idx,
const uint8_t key[16], int phase)
{
- json_object *jnode;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
+ struct mesh_node *node = mesh_net_node_get(net);
+ json_object *jnode = node_jconfig_get(node);
return mesh_db_net_key_add(jnode, net_idx, key, phase);
}
-bool storage_local_net_key_del(struct mesh_net *net, uint16_t net_idx)
+bool storage_net_key_del(struct mesh_net *net, uint16_t net_idx)
{
- json_object *jnode;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
+ struct mesh_node *node = mesh_net_node_get(net);
+ json_object *jnode = node_jconfig_get(node);
return mesh_db_net_key_del(jnode, net_idx);
}
-bool storage_local_set_iv_index(struct mesh_net *net, uint32_t iv_index,
+bool storage_set_iv_index(struct mesh_net *net, uint32_t iv_index,
bool update)
{
- json_object *jnode;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
+ struct mesh_node *node = mesh_net_node_get(net);
+ json_object *jnode = node_jconfig_get(node);
return mesh_db_write_iv_index(jnode, iv_index, update);
}
-bool storage_local_set_device_key(struct mesh_net *net, uint8_t dev_key[16])
-{
- json_object *jnode;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
- return mesh_db_write_device_key(jnode, dev_key);
-}
-
-bool storage_local_set_unicast(struct mesh_net *net, uint16_t unicast)
+bool storage_write_sequence_number(struct mesh_net *net, uint32_t seq)
{
- json_object *jnode;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
- return mesh_db_write_uint16_hex(jnode, "unicastAddress", unicast);
-}
-
-bool storage_local_write_sequence_number(struct mesh_net *net, uint32_t seq)
-{
- json_object *jnode;
- const char *cfg_file;
+ struct mesh_node *node = mesh_net_node_get(net);
+ json_object *jnode = node_jconfig_get(node);
bool result;
-
- if (!net)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
+ l_debug("");
result = mesh_db_write_int(jnode, "sequenceNumber", seq);
if (!result)
return false;
- result = mesh_net_cfg_file_get(net, &cfg_file);
- if (result && cfg_file)
- result = storage_save_config(net, cfg_file, false, NULL, NULL);
+ result = storage_save_config(node, false, NULL, NULL);
return result;
}
-static bool save_config(struct mesh_net *net, const char *config_name)
+static bool save_config(json_object *jnode, const char *config_name)
{
FILE *outfile;
const char *str;
- json_object *jnode;
bool result = false;
- if (!net || !config_name)
- return false;
-
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
- return false;
-
outfile = fopen(config_name, "w");
if (!outfile) {
l_error("Failed to save configuration to %s", config_name);
@@ -581,13 +365,6 @@ static bool save_config(struct mesh_net *net, const char *config_name)
return result;
}
-struct write_info {
- const char *config_name;
- struct mesh_net *net;
- void *user_data;
- mesh_status_func_t cb;
-};
-
static void idle_save_config(void *user_data)
{
struct write_info *info = user_data;
@@ -603,7 +380,7 @@ static void idle_save_config(void *user_data)
remove(tmp);
l_debug("Storage-Wrote");
- result = save_config(info->net, tmp);
+ result = save_config(info->jnode, tmp);
if (result) {
remove(bak);
@@ -621,48 +398,203 @@ static void idle_save_config(void *user_data)
l_free(info);
}
-bool storage_save_config(struct mesh_net *net, const char *config_name,
- bool no_wait, mesh_status_func_t cb, void *user_data)
+bool storage_save_config(struct mesh_node *node, bool no_wait,
+ mesh_status_func_t cb, void *user_data)
{
struct write_info *info;
info = l_new(struct write_info, 1);
if (!info)
return false;
-
- info->net = net;
- info->config_name = config_name;
+ l_debug("");
+ info->jnode = node_jconfig_get(node);
+ info->config_name = node_cfg_file_get(node);
info->cb = cb;
info->user_data = user_data;
if (no_wait)
idle_save_config(info);
- l_idle_oneshot(idle_save_config, info, NULL);
+ else
+ l_idle_oneshot(idle_save_config, info, NULL);
return true;
}
-bool storage_save_new_config(struct mesh_net *net, const char *config_name,
- mesh_status_func_t cb, void *user_data)
+static int create_dir(const char *dirname)
{
- json_object *jnode;
+ struct stat st;
+ char dir[PATH_MAX + 1], *prev, *next;
+ int err;
- jnode = mesh_net_jconfig_get(net);
- if (!jnode)
+ err = stat(dirname, &st);
+ if (!err && S_ISREG(st.st_mode))
+ return 0;
+
+ memset(dir, 0, PATH_MAX + 1);
+ strcat(dir, "/");
+
+ prev = strchr(dirname, '/');
+
+ while (prev) {
+ next = strchr(prev + 1, '/');
+ if (!next)
+ break;
+
+ if (next - prev == 1) {
+ prev = next;
+ continue;
+ }
+
+ strncat(dir, prev + 1, next - prev);
+ mkdir(dir, 0755);
+
+ prev = next;
+ }
+
+ mkdir(dirname, 0755);
+
+ return 0;
+}
+
+bool storage_load_nodes(const char *dir_name)
+{
+ DIR *dir;
+ struct dirent *entry;
+
+ create_dir(dir_name);
+ dir = opendir(dir_name);
+ if (!dir) {
+ l_error("Failed to open mesh node storage directory: %s",
+ dir_name);
return false;
+ }
+
+ storage_dir = dir_name;
+ node_ids = l_queue_new();
+
+ while ((entry = readdir(dir)) != NULL) {
+ char name_buf[PATH_MAX];
+ char *filename;
+ uint32_t node_id;
+ size_t len;
+
+ if (entry->d_type != DT_DIR)
+ continue;
+
+ if (sscanf(entry->d_name, "%04x", &node_id) != 1)
+ continue;
+
+ snprintf(name_buf, PATH_MAX, "%s/%s/node.json", dir_name,
+ entry->d_name);
+
+ l_queue_push_tail(node_ids, L_UINT_TO_PTR(node_id));
+
+ len = strlen(name_buf);
+ filename = l_malloc(len + 1);
+
+ strncpy(filename, name_buf, len + 1);
+
+ if (parse_config(name_buf, filename, node_id))
+ continue;
+
+ /* Fall-back to Backup version */
+ snprintf(name_buf, PATH_MAX, "%s/%s/node.json.bak", dir_name,
+ entry->d_name);
- mesh_db_remove_property(jnode, "provision");
+ if (parse_config(name_buf, filename, node_id)) {
+ remove(filename);
+ rename(name_buf, filename);
+ continue;
+ }
- return storage_save_config(net, config_name, false, cb, user_data);
+ l_free(filename);
+ }
+
+ return true;
}
-void storage_release(struct mesh_net *net)
+bool storage_create_node_config(struct mesh_node *node, void *data)
{
+ struct mesh_db_node *db_node = data;
+ uint16_t node_id;
+ uint8_t num_tries = 0;
+ char name_buf[PATH_MAX];
+ char *filename;
json_object *jnode;
+ size_t len;
+
+ if (!storage_dir)
+ return false;
+
+ jnode = json_object_new_object();
+
+ if (!mesh_db_add_node(jnode, db_node))
+ return false;
+
+
+
+ do {
+ l_getrandom(&node_id, 2);
+ if (!l_queue_find(node_ids, simple_match,
+ L_UINT_TO_PTR(node_id)))
+ break;
+ } while (++num_tries < 10);
+
+ if (num_tries == 10) {
+ l_error("Failed to generate unique node ID");
+
+ }
+
+ snprintf(name_buf, PATH_MAX, "%s/%04x", storage_dir, node_id);
+
+ /* Create a new directory and node.json file */
+ if (mkdir(name_buf, 0755) != 0)
+ goto fail;
- jnode = mesh_net_jconfig_get(net);
+ len = strlen(name_buf) + strlen("/node.json") + 1;
+ filename = l_malloc(len);
+
+ snprintf(filename, len, "%s/node.json", name_buf);
+ l_debug("New node config %s", filename);
+
+ if (!save_config(jnode, filename)) {
+ l_free(filename);
+ goto fail;
+ }
+
+ node_jconfig_set(node, jnode);
+ node_cfg_file_set(node, filename);
+
+ return true;
+fail:
+ json_object_put(jnode);
+ return false;
+}
+
+/* Permanently remove node configuration */
+void storage_remove_node_config(struct mesh_node *node)
+{
+ char *cfgname;
+ struct json_object *jnode;
+ const char *dir_name;
+
+ jnode = node_jconfig_get(node);
if (jnode)
json_object_put(jnode);
+ node_jconfig_set(node, NULL);
+
+ cfgname = (char *) node_cfg_file_get(node);
+ if (!cfgname)
+ return;
+
+ l_debug("Delete node config file %s", cfgname);
+ remove(cfgname);
+
+ dir_name = dirname(cfgname);
+
+ l_debug("Delete directory %s", dir_name);
+ rmdir(dir_name);
- mesh_net_jconfig_set(net, NULL);
+ l_free(cfgname);
+ node_cfg_file_set(node, NULL);
}
diff --git a/mesh/storage.h b/mesh/storage.h
index 341932dba..9583669f0 100644
--- a/mesh/storage.h
+++ b/mesh/storage.h
@@ -18,34 +18,35 @@
*
*/
+#include <json-c/json.h>
+
struct mesh_net;
+struct mesh_node;
-bool storage_parse_config(struct mesh_net *net, const char *config_name);
-bool storage_save_config(struct mesh_net *net, const char *config_name,
- bool no_wait, mesh_status_func_t cb, void *user_data);
-bool storage_save_new_config(struct mesh_net *net, const char *config_name,
+bool storage_load_nodes(const char *dir);
+bool storage_create_node_config(struct mesh_node *node, void *db_node);
+void storage_remove_node_config(struct mesh_node *node);
+bool storage_save_config(struct mesh_node *node, bool no_wait,
mesh_status_func_t cb, void *user_data);
-void storage_release(struct mesh_net *net);
-
-bool storage_model_bind(struct mesh_net *net, uint16_t addr, uint32_t id,
+bool storage_model_bind(struct mesh_node *node, uint16_t addr, uint32_t id,
uint16_t app_idx, bool unbind);
-bool storage_local_set_ttl(struct mesh_net *net, uint8_t ttl);
-bool storage_local_set_relay(struct mesh_net *net, bool enable, uint8_t count,
+bool storage_set_ttl(json_object *jnode, uint8_t ttl);
+bool storage_set_relay(json_object *jnode, bool enable, uint8_t count,
uint8_t interval);
-bool storage_local_set_transmit_params(struct mesh_net *net, uint8_t count,
+bool storage_set_transmit_params(json_object *jnode, uint8_t count,
uint8_t interval);
-bool storage_local_set_mode(struct mesh_net *net, uint8_t mode,
+bool storage_set_mode(json_object *jnode, uint8_t mode,
const char *mode_name);
-bool storage_local_net_key_add(struct mesh_net *net, uint16_t net_idx,
+bool storage_net_key_add(struct mesh_net *net, uint16_t net_idx,
const uint8_t key[16], int phase);
-bool storage_local_net_key_del(struct mesh_net *net, uint16_t net_idx);
-bool storage_local_app_key_add(struct mesh_net *net, uint16_t net_idx,
+bool storage_net_key_del(struct mesh_net *net, uint16_t net_idx);
+bool storage_app_key_add(struct mesh_net *net, uint16_t net_idx,
uint16_t app_idx, const uint8_t key[16], bool update);
-bool storage_local_app_key_del(struct mesh_net *net, uint16_t net_idx,
+bool storage_app_key_del(struct mesh_net *net, uint16_t net_idx,
uint16_t app_idx);
-bool storage_local_write_sequence_number(struct mesh_net *net, uint32_t seq);
-bool storage_local_set_iv_index(struct mesh_net *net, uint32_t iv_index,
+bool storage_write_sequence_number(struct mesh_net *net, uint32_t seq);
+bool storage_set_iv_index(struct mesh_net *net, uint32_t iv_index,
bool update);
-bool storage_local_set_device_key(struct mesh_net *net, uint8_t dev_key[16]);
-bool storage_local_set_unicast(struct mesh_net *net, uint16_t unicast);
+bool storage_set_device_key(struct mesh_node *node, uint8_t dev_key[16]);
+bool storage_set_unicast(struct mesh_node *node, uint16_t unicast);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 06/30] mesh: Rewrite Node handling for multiple nodes
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (4 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 05/30] mesh: Re-write storage for Multiple Nodes Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 07/30] mesh: Rewite Network layer " Brian Gix
` (23 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/node.c | 1338 +++++++++++++++++++++++++++++++++++++++++++++++++----------
mesh/node.h | 42 +-
2 files changed, 1158 insertions(+), 222 deletions(-)
diff --git a/mesh/node.c b/mesh/node.c
index 501ab8eea..0274f5b8d 100644
--- a/mesh/node.c
+++ b/mesh/node.c
@@ -22,21 +22,40 @@
#include <config.h>
#endif
+#include <stdio.h>
#include <sys/time.h>
#include <ell/ell.h>
#include "mesh/mesh-defs.h"
#include "mesh/mesh.h"
+#include "mesh/mesh-io.h"
#include "mesh/net.h"
-#include "mesh/node.h"
+#include "mesh/mesh-db.h"
+#include "mesh/provision.h"
#include "mesh/storage.h"
#include "mesh/appkey.h"
#include "mesh/model.h"
+#include "mesh/cfgmod.h"
+#include "mesh/util.h"
+#include "mesh/error.h"
+#include "mesh/dbus.h"
+#include "mesh/agent.h"
+#include "mesh/node.h"
#define MIN_COMP_SIZE 14
+#define MESH_NODE_PATH_PREFIX "/node"
+#define MESH_ELEMENT_PATH_PREFIX "/ele"
+
+/* Default element location: unknown */
+#define DEFAULT_LOCATION 0x0000
+
+#define DEFAULT_CRPL 10
+#define DEFAULT_SEQUENCE_NUMBER 0
+
struct node_element {
+ char *path;
struct l_queue *models;
uint16_t location;
uint8_t idx;
@@ -51,30 +70,45 @@ struct node_composition {
struct mesh_node {
struct mesh_net *net;
- struct l_queue *net_keys;
- struct l_queue *app_keys;
struct l_queue *elements;
+ char *app_path;
+ char *owner;
+ char *path;
+ void *jconfig;
+ char *cfg_file;
+ uint32_t disc_watch;
time_t upd_sec;
uint32_t seq_number;
uint32_t seq_min_cache;
- uint16_t primary;
- uint16_t num_ele;
- uint8_t dev_uuid[16];
- uint8_t dev_key[16];
- uint8_t ttl;
+ uint16_t id;
bool provisioner;
+ uint16_t primary;
struct node_composition *comp;
struct {
uint16_t interval;
uint8_t cnt;
uint8_t mode;
} relay;
+ uint8_t dev_uuid[16];
+ uint8_t dev_key[16];
+ uint8_t num_ele;
+ uint8_t ttl;
uint8_t lpn;
uint8_t proxy;
uint8_t friend;
uint8_t beacon;
};
+struct attach_obj_request {
+ node_attach_ready_func_t cb;
+ struct mesh_node *node;
+};
+
+struct join_obj_request {
+ node_join_ready_func_t cb;
+ const uint8_t *uuid;
+};
+
static struct l_queue *nodes;
static bool match_node_unicast(const void *a, const void *b)
@@ -94,6 +128,14 @@ static bool match_device_uuid(const void *a, const void *b)
return (memcmp(node->dev_uuid, uuid, 16) == 0);
}
+static bool match_token(const void *a, const void *b)
+{
+ const struct mesh_node *node = a;
+ const uint64_t *token = b;
+ const uint64_t tmp = l_get_u64(node->dev_key);
+ return *token == tmp;
+}
+
static bool match_element_idx(const void *a, const void *b)
{
const struct node_element *element = a;
@@ -102,17 +144,15 @@ static bool match_element_idx(const void *a, const void *b)
return (element->idx == index);
}
-static bool match_key_idx(const void *a, const void *b)
+static bool match_element_path(const void *a, const void *b)
{
- return (L_PTR_TO_UINT(a) == L_PTR_TO_UINT(b));
-}
+ const struct node_element *element = a;
+ const char *path = b;
-static bool match_model_id(const void *a, const void *b)
-{
- const struct mesh_model *model = a;
- uint32_t id = L_PTR_TO_UINT(b);
+ if (!element->path)
+ return false;
- return (mesh_model_get_model_id(model) == id);
+ return (!strcmp(element->path, path));
}
struct mesh_node *node_find_by_addr(uint16_t addr)
@@ -140,20 +180,30 @@ struct mesh_node *node_new(void)
struct mesh_node *node;
node = l_new(struct mesh_node, 1);
+ node->net = mesh_net_new(node);
- if (!node)
- return NULL;
+ if (!nodes)
+ nodes = l_queue_new();
l_queue_push_tail(nodes, node);
return node;
}
+static void free_element_path(void *a, void *b)
+{
+ struct node_element *element = a;
+
+ l_free(element->path);
+ element->path = NULL;
+}
+
static void element_free(void *data)
{
struct node_element *element = data;
l_queue_destroy(element->models, mesh_model_free);
+ l_free(element->path);
l_free(element);
}
@@ -161,13 +211,20 @@ static void free_node_resources(void *data)
{
struct mesh_node *node = data;
- l_queue_destroy(node->net_keys, NULL);
- l_queue_destroy(node->app_keys, NULL);
+ /* Unregister io callbacks */
+ if(node->net)
+ mesh_net_detach(node->net);
+ mesh_net_free(node->net);
+
l_queue_destroy(node->elements, element_free);
l_free(node->comp);
+ l_free(node->app_path);
+ l_free(node->owner);
- if (node->net)
- mesh_net_unref(node->net);
+ if (node->path)
+ l_dbus_object_remove_interface(dbus_get_bus(), node->path,
+ MESH_NODE_INTERFACE);
+ l_free(node->path);
l_free(node);
}
@@ -176,19 +233,18 @@ void node_free(struct mesh_node *node)
{
if (!node)
return;
+
l_queue_remove(nodes, node);
free_node_resources(node);
}
-static bool add_models(struct mesh_net *net, struct node_element *ele,
+static bool add_models(struct mesh_node *node, struct node_element *ele,
struct mesh_db_element *db_ele)
{
const struct l_queue_entry *entry;
if (!ele->models)
ele->models = l_queue_new();
- if (!ele->models)
- return false;
entry = l_queue_get_entries(db_ele->models);
for (; entry; entry = entry->next) {
@@ -196,7 +252,7 @@ static bool add_models(struct mesh_net *net, struct node_element *ele,
struct mesh_db_model *db_mod;
db_mod = entry->data;
- mod = mesh_model_init(net, ele->idx, db_mod);
+ mod = mesh_model_setup(node, ele->idx, db_mod);
if (!mod)
return false;
@@ -206,6 +262,32 @@ static bool add_models(struct mesh_net *net, struct node_element *ele,
return true;
}
+static void add_internal_model(struct mesh_node *node, uint32_t mod_id,
+ uint8_t ele_idx)
+{
+ struct node_element *ele;
+ struct mesh_model *mod;
+ struct mesh_db_model db_mod;
+
+ ele = l_queue_find(node->elements, match_element_idx,
+ L_UINT_TO_PTR(ele_idx));
+
+ if (!ele)
+ return;
+
+ memset(&db_mod, 0, sizeof(db_mod));
+ db_mod.id = mod_id;
+
+ mod = mesh_model_setup(node, ele_idx, &db_mod);
+ if (!mod)
+ return;
+
+ if (!ele->models)
+ ele->models = l_queue_new();
+
+ l_queue_push_tail(ele->models, mod);
+}
+
static bool add_element(struct mesh_node *node, struct mesh_db_element *db_ele)
{
struct node_element *ele;
@@ -217,7 +299,7 @@ static bool add_element(struct mesh_node *node, struct mesh_db_element *db_ele)
ele->idx = db_ele->index;
ele->location = db_ele->location;
- if (!db_ele->models || !add_models(node->net, ele, db_ele))
+ if (!db_ele->models || !add_models(node, ele, db_ele))
return false;
l_queue_push_tail(node->elements, ele);
@@ -231,9 +313,6 @@ static bool add_elements(struct mesh_node *node, struct mesh_db_node *db_node)
if (!node->elements)
node->elements = l_queue_new();
- if (!node->elements)
- return false;
-
entry = l_queue_get_entries(db_node->elements);
for (; entry; entry = entry->next)
if (!add_element(node, entry->data))
@@ -242,26 +321,12 @@ static bool add_elements(struct mesh_node *node, struct mesh_db_node *db_node)
return true;
}
-struct mesh_node *node_create_from_storage(struct mesh_net *net,
- struct mesh_db_node *db_node,
- bool local)
+bool node_init_from_storage(struct mesh_node *node, void *data)
{
- struct mesh_node *node;
+ struct mesh_db_node *db_node = data;
unsigned int num_ele;
- if (local && !net)
- return NULL;
-
- node = node_new();
- if (!node)
- return NULL;
-
node->comp = l_new(struct node_composition, 1);
- if (!node->comp) {
- node_free(node);
- return NULL;
- }
-
node->comp->cid = db_node->cid;
node->comp->pid = db_node->pid;
node->comp->vid = db_node->vid;
@@ -276,107 +341,77 @@ struct mesh_node *node_create_from_storage(struct mesh_net *net,
node->relay.interval = db_node->modes.relay.interval;
node->beacon = db_node->modes.beacon;
- l_info("relay %2.2x, proxy %2.2x, lpn %2.2x, friend %2.2x",
- node->relay.mode, node->proxy, node->friend, node->lpn);
+ l_debug("relay %2.2x, proxy %2.2x, lpn %2.2x, friend %2.2x",
+ node->relay.mode, node->proxy, node->friend, node->lpn);
node->ttl = db_node->ttl;
node->seq_number = db_node->seq_number;
num_ele = l_queue_length(db_node->elements);
- if (num_ele > 0xff) {
- node_free(node);
- return NULL;
- }
+ if (num_ele > 0xff)
+ return false;
node->num_ele = num_ele;
- if (num_ele != 0 && !add_elements(node, db_node)) {
- node_free(node);
- return NULL;
- }
+ if (num_ele != 0 && !add_elements(node, db_node))
+ return false;
node->primary = db_node->unicast;
memcpy(node->dev_uuid, db_node->uuid, 16);
- if (local)
- node->net = mesh_net_ref(net);
+ /* Initialize configuration server model */
+ mesh_config_srv_init(node, PRIMARY_ELE_IDX);
- return node;
+ return true;
}
-void node_cleanup(struct mesh_net *net)
+void node_cleanup(void *data)
{
- struct mesh_node *node;
+ struct mesh_node *node = data;
+ struct mesh_net *net = node->net;
- if (!net)
- return;
- node = mesh_net_local_node_get(net);
- if (node)
- node_free(node);
+ /* Save local node configuration */
+ if (node->cfg_file) {
+
+ /* Preserve the last sequence number */
+ storage_write_sequence_number(net, mesh_net_get_seq_num(net));
- l_queue_destroy(nodes, free_node_resources);
+ if (storage_save_config(node, true, NULL, NULL))
+ l_info("Saved final config to %s", node->cfg_file);
+ }
+
+ if (node->disc_watch)
+ dbus_disconnect_watch_remove(dbus_get_bus(), node->disc_watch);
+ free_node_resources(node);
}
-bool node_is_provisioned(struct mesh_node *node)
+void node_cleanup_all(void)
{
- return (!IS_UNASSIGNED(node->primary));
+ l_queue_destroy(nodes, node_cleanup);
+ l_dbus_unregister_interface(dbus_get_bus(), MESH_NODE_INTERFACE);
}
-bool node_net_key_delete(struct mesh_node *node, uint16_t idx)
+bool node_is_provisioned(struct mesh_node *node)
{
- if (!node)
- return false;
-
- if (!l_queue_find(node->net_keys, match_key_idx, L_UINT_TO_PTR(idx)))
- return false;
-
- l_queue_remove(node->net_keys, L_UINT_TO_PTR(idx));
- /* TODO: remove all associated app keys and bindings */
- return true;
+ return (!IS_UNASSIGNED(node->primary));
}
bool node_app_key_delete(struct mesh_net *net, uint16_t addr,
uint16_t net_idx, uint16_t app_idx)
{
struct mesh_node *node;
- uint32_t index;
const struct l_queue_entry *entry;
node = node_find_by_addr(addr);
if (!node)
return false;
- index = (net_idx << 16) + app_idx;
-
- if (!l_queue_find(node->app_keys, match_key_idx, L_UINT_TO_PTR(index)))
- return false;
-
- l_queue_remove(node->app_keys, L_UINT_TO_PTR(index));
-
- storage_local_app_key_del(net, net_idx, app_idx);
-
entry = l_queue_get_entries(node->elements);
for (; entry; entry = entry->next) {
struct node_element *ele = entry->data;
- mesh_model_app_key_delete(net, ele->models, app_idx);
+ mesh_model_app_key_delete(node, ele->models, app_idx);
}
-
- return true;
-}
-
-bool node_set_primary(struct mesh_node *node, uint16_t unicast)
-{
- if (!node)
- return false;
-
- node->primary = unicast;
-
- /* If local node, save to storage */
- if (node->net)
- return storage_local_set_unicast(node->net, unicast);
-
- /* TODO: for provisioner, store remote node info */
return true;
}
@@ -388,20 +423,9 @@ uint16_t node_get_primary(struct mesh_node *node)
return node->primary;
}
-bool node_set_device_key(struct mesh_node *node, uint8_t key[16])
-
+void node_set_device_key(struct mesh_node *node, uint8_t key[16])
{
- if (!node || !key)
- return false;
-
memcpy(node->dev_key, key, 16);
-
- /* If local node, save to storage */
- if (node->net)
- return storage_local_set_device_key(node->net, key);
-
- /* TODO: for provisioner, store remote node info */
- return true;
}
const uint8_t *node_get_device_key(struct mesh_node *node)
@@ -417,22 +441,6 @@ uint8_t node_get_num_elements(struct mesh_node *node)
return node->num_ele;
}
-struct l_queue *node_get_net_keys(struct mesh_node *node)
-{
- if (!node)
- return NULL;
- else
- return node->net_keys;
-}
-
-struct l_queue *node_get_app_keys(struct mesh_node *node)
-{
- if (!node)
- return NULL;
- else
- return node->app_keys;
-}
-
struct l_queue *node_get_element_models(struct mesh_node *node,
uint8_t ele_idx, int *status)
{
@@ -458,31 +466,6 @@ struct l_queue *node_get_element_models(struct mesh_node *node,
return ele->models;
}
-struct mesh_model *node_get_model(struct mesh_node *node, uint8_t ele_idx,
- uint32_t id, int *status)
-{
- struct l_queue *models;
- struct mesh_model *model;
-
- if (!node) {
- if (status)
- *status = MESH_STATUS_INVALID_ADDRESS;
- return NULL;
- }
-
- models = node_get_element_models(node, ele_idx, status);
- if (!models)
- return NULL;
-
- model = l_queue_find(models, match_model_id, L_UINT_TO_PTR(id));
-
- if (status)
- *status = (model) ? MESH_STATUS_SUCCESS :
- MESH_STATUS_INVALID_MODEL;
-
- return model;
-}
-
uint8_t node_default_ttl_get(struct mesh_node *node)
{
if (!node)
@@ -492,20 +475,16 @@ uint8_t node_default_ttl_get(struct mesh_node *node)
bool node_default_ttl_set(struct mesh_node *node, uint8_t ttl)
{
- bool res, is_local;
+ bool res;
if (!node)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
- res = storage_local_set_ttl(node->net, ttl);
+ res = storage_set_ttl(node->jconfig, ttl);
if (res) {
node->ttl = ttl;
- if (is_local)
- mesh_net_set_default_ttl(node->net, ttl);
+ mesh_net_set_default_ttl(node->net, ttl);
}
return res;
@@ -513,21 +492,13 @@ bool node_default_ttl_set(struct mesh_node *node, uint8_t ttl)
bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
{
- bool is_local;
struct timeval write_time;
-
if (!node)
return false;
node->seq_number = seq;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
- if (!is_local)
- return true;
-
/*
* Holistically determine worst case 5 minute sequence consumption
* so that we typically (once we reach a steady state) rewrite the
@@ -541,7 +512,7 @@ bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
if (elapsed < MIN_SEQ_CACHE_TIME) {
uint32_t ideal = node->seq_min_cache;
- l_info("Old Seq Cache: %d", node->seq_min_cache);
+ l_debug("Old Seq Cache: %d", node->seq_min_cache);
ideal *= (MIN_SEQ_CACHE_TIME / elapsed);
@@ -550,14 +521,13 @@ bool node_set_sequence_number(struct mesh_node *node, uint32_t seq)
else
node->seq_min_cache += MIN_SEQ_CACHE;
- l_info("New Seq Cache: %d", node->seq_min_cache);
+ l_debug("New Seq Cache: %d", node->seq_min_cache);
}
}
node->upd_sec = write_time.tv_sec;
- l_info("Storage-Write");
- return storage_local_write_sequence_number(node->net, seq);
+ return storage_write_sequence_number(node->net, seq);
}
uint32_t node_get_sequence_number(struct mesh_node *node)
@@ -629,24 +599,19 @@ uint8_t node_lpn_mode_get(struct mesh_node *node)
bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
uint16_t interval)
{
- bool res, is_local;
+ bool res;
if (!node || node->relay.mode == MESH_MODE_UNSUPPORTED)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
- res = storage_local_set_relay(node->net, enable, cnt, interval);
+ res = storage_set_relay(node->jconfig, enable, cnt, interval);
if (res) {
node->relay.mode = enable ? MESH_MODE_ENABLED :
MESH_MODE_DISABLED;
node->relay.cnt = cnt;
node->relay.interval = interval;
- if (is_local)
- mesh_net_set_relay_mode(node->net, enable, cnt,
- interval);
+ mesh_net_set_relay_mode(node->net, enable, cnt, interval);
}
return res;
@@ -654,22 +619,18 @@ bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
bool node_proxy_mode_set(struct mesh_node *node, bool enable)
{
- bool res, is_local;
+ bool res;
uint8_t proxy;
if (!node || node->proxy == MESH_MODE_UNSUPPORTED)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
proxy = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
- res = storage_local_set_mode(node->net, proxy, "proxy");
+ res = storage_set_mode(node->jconfig, proxy, "proxy");
if (res) {
node->proxy = proxy;
- if (is_local)
- mesh_net_set_proxy_mode(node->net, enable);
+ mesh_net_set_proxy_mode(node->net, enable);
}
return res;
@@ -685,22 +646,18 @@ uint8_t node_proxy_mode_get(struct mesh_node *node)
bool node_beacon_mode_set(struct mesh_node *node, bool enable)
{
- bool res, is_local;
+ bool res;
uint8_t beacon;
if (!node)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
beacon = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
- res = storage_local_set_mode(node->net, beacon, "beacon");
+ res = storage_set_mode(node->jconfig, beacon, "beacon");
if (res) {
node->beacon = beacon;
- if (is_local)
- mesh_net_set_beacon_mode(node->net, enable);
+ mesh_net_set_beacon_mode(node->net, enable);
}
return res;
@@ -716,22 +673,18 @@ uint8_t node_beacon_mode_get(struct mesh_node *node)
bool node_friend_mode_set(struct mesh_node *node, bool enable)
{
- bool res, is_local;
+ bool res;
uint8_t friend;
if (!node || node->friend == MESH_MODE_UNSUPPORTED)
return false;
- is_local = (node->net && mesh_net_local_node_get(node->net) == node) ?
- true : false;
-
friend = enable ? MESH_MODE_ENABLED : MESH_MODE_DISABLED;
- res = storage_local_set_mode(node->net, friend, "friend");
+ res = storage_set_mode(node->jconfig, friend, "friend");
if (res) {
node->friend = friend;
- if (is_local)
- mesh_net_set_friend_mode(node->net, enable);
+ mesh_net_set_friend_mode(node->net, enable);
}
return res;
@@ -788,7 +741,7 @@ uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz)
/* At least fit location and zeros for number of models */
if ((n + 4) > sz)
return n;
- l_info("ele->location %d", ele->location);
+
l_put_le16(ele->location, buf + n);
n += 2;
@@ -805,7 +758,7 @@ uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz)
mod_id = mesh_model_get_model_id(
(const struct mesh_model *) mod);
- if ((mod_id >> 16) == 0xffff) {
+ if ((mod_id & VENDOR_ID_MASK) == VENDOR_ID_MASK) {
if (n + 2 > sz)
goto element_done;
@@ -849,3 +802,970 @@ element_done:
return n;
}
+
+
+#define MIN_COMPOSITION_LEN 16
+
+bool node_parse_composition(struct mesh_node *node, uint8_t *data,
+ uint16_t len)
+{
+ struct node_composition *comp;
+ uint16_t features;
+ uint8_t num_ele;
+ bool mode;
+
+ if (!len)
+ return false;
+
+ /* Skip page -- We only support Page Zero */
+ data++;
+ len--;
+
+ if (len < MIN_COMPOSITION_LEN)
+ return false;
+
+ comp = l_new(struct node_composition, 1);
+ if (!comp)
+ return false;
+
+ node->elements = l_queue_new();
+ if (!node->elements) {
+ l_free(comp);
+ return false;
+ }
+
+ node->comp = l_new(struct node_composition, 1);
+ comp->cid = l_get_le16(&data[0]);
+ comp->pid = l_get_le16(&data[2]);
+ comp->vid = l_get_le16(&data[4]);
+ comp->crpl = l_get_le16(&data[6]);
+ features = l_get_le16(&data[8]);
+ data += 10;
+ len -= 10;
+
+ mode = !!(features & FEATURE_PROXY);
+ node->proxy = mode ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED;
+
+ mode = !!(features & FEATURE_LPN);
+ node->lpn = mode ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED;
+
+ mode = !!(features & FEATURE_FRIEND);
+ node->friend = mode ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED;
+
+ mode = !!(features & FEATURE_RELAY);
+ node->relay.mode = mode ? MESH_MODE_DISABLED : MESH_MODE_UNSUPPORTED;
+
+ num_ele = 0;
+
+ do {
+ uint8_t m, v;
+ uint16_t mod_id;
+ uint16_t vendor_id;
+ struct node_element *ele;
+ struct mesh_model *mod;
+
+ ele = l_new(struct node_element, 1);
+ if (!ele)
+ return false;
+
+ ele->idx = num_ele;
+ ele->location = l_get_le16(data);
+ len -= 2;
+ data += 2;
+
+ m = *data++;
+ v = *data++;
+ len -= 2;
+
+ /* Parse SIG models */
+ while (len >= 2 && m--) {
+ mod_id = l_get_le16(data);
+ mod = mesh_model_new(ele->idx, mod_id);
+ if (!mod) {
+ element_free(ele);
+ goto fail;
+ }
+
+ l_queue_push_tail(ele->models, mod);
+ data += 2;
+ len -= 2;
+ }
+
+ if (v && len < 4) {
+ element_free(ele);
+ goto fail;
+ }
+
+ /* Parse vendor models */
+ while (len >= 4 && v--) {
+ mod_id = l_get_le16(data + 2);
+ vendor_id = l_get_le16(data);
+ mod_id |= (vendor_id << 16);
+ mod = mesh_model_vendor_new(ele->idx, vendor_id,
+ mod_id);
+ if (!mod) {
+ element_free(ele);
+ goto fail;
+ }
+
+ l_queue_push_tail(ele->models, mod);
+ data += 4;
+ len -= 4;
+ }
+
+ num_ele++;
+ l_queue_push_tail(node->elements, ele);
+
+ } while (len >= 6);
+
+ /* Check the consistency for the remote node */
+ if (node->num_ele > num_ele)
+ goto fail;
+
+ node->comp = comp;
+ node->num_ele = num_ele;
+
+ return true;
+
+fail:
+ l_queue_destroy(node->elements, element_free);
+ l_free(comp);
+
+ return false;
+}
+
+void node_id_set(struct mesh_node *node, uint16_t id)
+{
+ if (node)
+ node->id = id;
+}
+
+static void attach_io(void *a, void *b)
+{
+ struct mesh_node *node = a;
+ struct mesh_io *io = b;
+
+ if (node->net)
+ mesh_net_attach(node->net, io);
+}
+
+/* Register callbacks for io */
+void node_attach_io(struct mesh_io *io)
+{
+ l_queue_foreach(nodes, attach_io, io);
+}
+
+static bool register_node_object(struct mesh_node *node)
+{
+ node->path = l_malloc(strlen(MESH_NODE_PATH_PREFIX) + 5);
+
+ snprintf(node->path, 10, MESH_NODE_PATH_PREFIX "%4.4x", node->id);
+
+ if (!l_dbus_object_add_interface(dbus_get_bus(), node->path,
+ MESH_NODE_INTERFACE, node))
+ return false;
+
+ return true;
+}
+
+static void app_disc_cb(struct l_dbus *bus, void *user_data)
+{
+ struct mesh_node *node = user_data;
+
+ l_info("App %s disconnected (%u)", node->owner, node->disc_watch);
+
+ node->disc_watch = 0;
+
+ l_queue_foreach(node->elements, free_element_path, NULL);
+
+ l_free(node->owner);
+ node->owner = NULL;
+
+ l_free(node->app_path);
+ node->app_path = NULL;
+}
+
+static bool validate_element_properties(struct mesh_node *node,
+ const char *path,
+ struct l_dbus_message_iter *properties)
+{
+ uint8_t ele_idx;
+ struct node_element *ele;
+ const char *key;
+ struct l_dbus_message_iter variant;
+ bool have_index = false;
+
+ l_debug("path %s", path);
+
+ while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+ if (!strcmp(key, "Index")) {
+ have_index = true;
+ break;
+ }
+ }
+
+ if (!have_index) {
+ l_debug("Mandatory property \"Index\" not found");
+ return false;
+ }
+
+ if (!l_dbus_message_iter_get_variant(&variant, "y", &ele_idx))
+ return false;
+
+ ele = l_queue_find(node->elements, match_element_idx,
+ L_UINT_TO_PTR(ele_idx));
+
+ if (!ele) {
+ l_debug("Element with index %u not found", ele_idx);
+ return false;
+ }
+
+ /* TODO: validate models */
+
+ ele->path = l_strdup(path);
+
+ return true;
+}
+
+static void get_managed_objects_attach_cb(struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct l_dbus_message_iter objects, interfaces;
+ struct attach_obj_request *req = user_data;
+ struct mesh_node *node = req->node;
+ const char *path;
+ uint64_t token = l_get_u64(node->dev_key);
+ uint8_t num_ele;
+
+ if (l_dbus_message_is_error(msg)) {
+ l_error("Failed to get app's dbus objects");
+ goto fail;
+ }
+
+ if (!l_dbus_message_get_arguments(msg, "a{oa{sa{sv}}}", &objects)) {
+ l_error("Failed to parse app's dbus objects");
+ goto fail;
+ }
+
+ num_ele = 0;
+
+ while (l_dbus_message_iter_next_entry(&objects, &path, &interfaces)) {
+ struct l_dbus_message_iter properties;
+ const char *interface;
+
+ while (l_dbus_message_iter_next_entry(&interfaces, &interface,
+ &properties)) {
+ if (strcmp(MESH_ELEMENT_INTERFACE, interface))
+ continue;
+
+ if (!validate_element_properties(node, path,
+ &properties))
+ goto fail;
+
+ num_ele++;
+ }
+ }
+
+ /*
+ * Check that the number of element objects matches the expected number
+ * of elements on the node
+ */
+ if (num_ele != node->num_ele)
+ goto fail;
+
+ /* Register node object with D-Bus */
+ register_node_object(node);
+
+ if (node->path) {
+ struct l_dbus *bus = dbus_get_bus();
+
+ node->disc_watch = dbus_disconnect_watch_add(bus, node->owner,
+ app_disc_cb, node);
+ req->cb(MESH_ERROR_NONE, node->path, token);
+
+ return;
+ }
+fail:
+ req->cb(MESH_ERROR_FAILED, NULL, token);
+
+ l_queue_foreach(node->elements, free_element_path, NULL);
+ l_free(node->app_path);
+ node->app_path = NULL;
+
+ l_free(node->owner);
+ node->owner = NULL;
+}
+
+/* Establish relationship between application and mesh node */
+int node_attach(const char *app_path, const char *sender, uint64_t token,
+ node_attach_ready_func_t cb)
+{
+ struct attach_obj_request *req;
+ struct mesh_node *node;
+
+ l_debug("");
+
+ node = l_queue_find(nodes, match_token, &token);
+ if (!node)
+ return MESH_ERROR_NOT_FOUND;
+
+ /* TODO: decide what to do if previous node->app_path is not NULL */
+ node->app_path = l_strdup(app_path);
+
+ node->owner = l_strdup(sender);
+
+ req = l_new(struct attach_obj_request, 1);
+ req->node = node;
+ req->cb = cb;
+
+ l_dbus_method_call(dbus_get_bus(), sender, app_path,
+ L_DBUS_INTERFACE_OBJECT_MANAGER,
+ "GetManagedObjects", NULL,
+ get_managed_objects_attach_cb,
+ req, l_free);
+ return MESH_ERROR_NONE;
+
+}
+
+static void add_model_from_properties(struct node_element *ele,
+ struct l_dbus_message_iter *property)
+{
+ struct l_dbus_message_iter ids;
+ uint16_t model_id;
+ int i = 0;
+
+ if (!ele->models)
+ ele->models = l_queue_new();
+
+ if (!l_dbus_message_iter_get_variant(property, "aq", &ids))
+ return;
+
+ while (l_dbus_message_iter_next_entry(&ids, &model_id)) {
+ struct mesh_model *mod;
+ l_debug("model_id %4.4x", model_id);
+ mod = mesh_model_new(ele->idx, model_id);
+ l_queue_push_tail(ele->models, mod);
+ i++;
+ if (i > 3)
+ break;
+ }
+}
+
+static void add_vendor_model_from_properties(struct node_element *ele,
+ struct l_dbus_message_iter *property)
+{
+ struct {
+ uint16_t v;
+ uint16_t m;
+ } id_pair;
+
+ if (!ele->models)
+ ele->models = l_queue_new();
+
+ while (l_dbus_message_iter_next_entry(property, &id_pair)) {
+ struct mesh_model *mod;
+ mod = mesh_model_vendor_new(ele->idx, id_pair.v, id_pair.m);
+ l_queue_push_tail(ele->models, mod);
+ }
+}
+
+static bool get_element_properties(struct mesh_node *node, const char *path,
+ struct l_dbus_message_iter *properties)
+{
+ struct node_element *ele;
+ const char *key;
+ struct l_dbus_message_iter variant;
+ bool have_index = false;
+
+ l_debug("path %s", path);
+
+ ele = l_new(struct node_element, 1);
+ ele->location = DEFAULT_LOCATION;
+
+ while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+ if (!strcmp(key, "Index")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "y",
+ &ele->idx))
+ return false;
+ have_index = true;
+ } else if (!strcmp(key, "Location")) {
+ l_dbus_message_iter_get_variant(&variant, "q",
+ &ele->location);
+ } else if (!strcmp(key, "Models")) {
+ add_model_from_properties(ele, &variant);
+ } else if (!strcmp(key, "VendorModels")) {
+ add_vendor_model_from_properties(ele, &variant);
+ }
+ }
+
+ if (!have_index) {
+ l_debug("Mandatory property \"Index\" not found");
+ return false;
+ }
+
+ l_queue_push_tail(node->elements, ele);
+
+ return true;
+}
+
+static bool get_app_properties(struct mesh_node *node, const char *path,
+ struct l_dbus_message_iter *properties)
+{
+ const char *key;
+ struct l_dbus_message_iter variant;
+
+ l_debug("path %s", path);
+
+ if (!node->comp)
+ node->comp = l_new(struct node_composition, 1);
+
+ while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+
+ if (!strcmp(key, "CompanyID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &node->comp->cid))
+ return false;
+ } else if (!strcmp(key, "ProductID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &node->comp->pid))
+ return false;
+ } else if (!strcmp(key, "VersionID")) {
+ if (!l_dbus_message_iter_get_variant(&variant, "q",
+ &node->comp->vid))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void convert_node_to_storage(struct mesh_node *node,
+ struct mesh_db_node *db_node)
+{
+ const struct l_queue_entry *entry;
+
+ db_node->cid = node->comp->cid;
+ db_node->pid = node->comp->pid;
+ db_node->vid = node->comp->vid;
+ db_node->crpl = node->comp->crpl;
+ db_node->modes.lpn = node->lpn;
+ db_node->modes.proxy = node->proxy;
+
+ memcpy(db_node->uuid, node->dev_uuid, 16);
+
+ node->friend = db_node->modes.friend;
+ db_node->modes.relay.state = node->relay.mode;
+ db_node->modes.relay.cnt = node->relay.cnt;
+ db_node->modes.relay.interval = node->relay.interval;
+ db_node->modes.beacon = node->beacon;
+
+ db_node->ttl = node->ttl;
+ db_node->seq_number = node->seq_number;
+
+ db_node->elements = l_queue_new();
+
+ entry = l_queue_get_entries(node->elements);
+
+ for (; entry; entry = entry->next) {
+ struct node_element *ele = entry->data;
+ struct mesh_db_element *db_ele;
+ const struct l_queue_entry *mod_entry;
+
+ db_ele = l_new(struct mesh_db_element, 1);
+
+ db_ele->index = ele->idx;
+ db_ele->location = ele->location;
+ db_ele->models = l_queue_new();
+
+ mod_entry = l_queue_get_entries(ele->models);
+
+ for (; mod_entry; mod_entry = mod_entry->next) {
+ struct mesh_model *mod = mod_entry->data;
+ struct mesh_db_model *db_mod;
+ uint32_t mod_id = mesh_model_get_model_id(mod);
+
+ db_mod = l_new(struct mesh_db_model, 1);
+ db_mod->id = mod_id;
+ db_mod->vendor = ((mod_id & VENDOR_ID_MASK)
+ != VENDOR_ID_MASK);
+
+ l_queue_push_tail(db_ele->models, db_mod);
+ }
+ l_queue_push_tail(db_node->elements, db_ele);
+ }
+
+}
+
+static bool create_node_config(struct mesh_node *node)
+{
+ struct mesh_db_node db_node;
+ const struct l_queue_entry *entry;
+ bool res;
+
+ convert_node_to_storage(node, &db_node);
+ res = storage_create_node_config(node, &db_node);
+
+ /* Free temporarily allocated resources */
+ entry = l_queue_get_entries(db_node.elements);
+ for (; entry; entry = entry->next) {
+ struct mesh_db_element *db_ele = entry->data;
+
+ l_queue_destroy(db_ele->models, l_free);
+ }
+
+ l_queue_destroy(db_node.elements, l_free);
+
+ return res;
+}
+
+static void set_defaults(struct mesh_node *node)
+{
+ /* TODO: these values should come from mesh.conf */
+ if (!node->comp)
+ node->comp = l_new(struct node_composition, 1);
+
+ node->comp->crpl = DEFAULT_CRPL;
+ node->lpn = MESH_MODE_UNSUPPORTED;
+ node->proxy = MESH_MODE_UNSUPPORTED;
+ node->friend = MESH_MODE_UNSUPPORTED;
+ node->beacon = MESH_MODE_DISABLED;
+ node->relay.mode = MESH_MODE_DISABLED;
+ node->ttl = DEFAULT_TTL;
+ node->seq_number = DEFAULT_SEQUENCE_NUMBER;
+
+ /* Add configuration server model on primary element */
+ add_internal_model(node, CONFIG_SRV_MODEL, PRIMARY_ELE_IDX);
+}
+
+static void get_managed_objects_join_cb(struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct l_dbus_message_iter objects, interfaces;
+ struct join_obj_request *req = user_data;
+ const char *path;
+ struct mesh_node *node = NULL;
+ void *agent = NULL;
+
+ if (l_dbus_message_is_error(msg)) {
+ l_error("Failed to get app's dbus objects");
+ goto fail;
+ }
+
+ if (!l_dbus_message_get_arguments(msg, "a{oa{sa{sv}}}", &objects)) {
+ l_error("Failed to parse app's dbus objects");
+ goto fail;
+ }
+
+ node = l_new(struct mesh_node, 1);
+ node->elements = l_queue_new();
+
+ while (l_dbus_message_iter_next_entry(&objects, &path, &interfaces)) {
+ struct l_dbus_message_iter properties;
+ const char *interface;
+
+ while (l_dbus_message_iter_next_entry(&interfaces, &interface,
+ &properties)) {
+ bool res;
+
+ if (!strcmp(MESH_ELEMENT_INTERFACE, interface)) {
+ res = get_element_properties(node, path,
+ &properties);
+ if (!res)
+ goto fail;
+
+ node->num_ele++;
+ continue;
+
+ }
+
+ if (!strcmp(MESH_APPLICATION_INTERFACE, interface)) {
+ res = get_app_properties(node, path,
+ &properties);
+ if (!res)
+ goto fail;
+
+ continue;
+ }
+
+ if (!strcmp(MESH_PROVISION_AGENT_INTERFACE,
+ interface)) {
+ const char *sender;
+
+ sender = l_dbus_message_get_sender(msg);
+ agent = mesh_agent_create(path, sender,
+ &properties);
+ if (!agent)
+ goto fail;
+ }
+ }
+ }
+
+ if (!node->comp){
+ l_error("Interface %s not found", MESH_APPLICATION_INTERFACE);
+ goto fail;
+ }
+
+ if (!agent) {
+ l_error("Interface %s not found",
+ MESH_PROVISION_AGENT_INTERFACE);
+ goto fail;
+ }
+
+ if (!node->num_ele) {
+ l_error("Interface %s not found", MESH_ELEMENT_INTERFACE);
+ goto fail;
+ }
+
+ if (!l_queue_find(node->elements, match_element_idx,
+ L_UINT_TO_PTR(PRIMARY_ELE_IDX))) {
+
+ l_debug("Primary element not detected");
+ goto fail;
+ }
+
+ set_defaults(node);
+ memcpy(node->dev_uuid, req->uuid, 16);
+
+ if (!create_node_config(node))
+ goto fail;
+
+ req->cb(node, agent);
+
+ return;
+fail:
+ if (agent)
+ free_node_resources(node);
+
+ if (node)
+ mesh_agent_remove(agent);
+
+ req->cb(NULL, NULL);
+}
+
+/* Create a temporary pre-provisioned node */
+void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
+ node_join_ready_func_t cb)
+{
+ struct join_obj_request *req;
+
+ l_debug("");
+
+ req = l_new(struct join_obj_request, 1);
+ req->uuid = uuid;
+ req->cb = cb;
+
+ l_dbus_method_call(dbus_get_bus(), sender, app_path,
+ L_DBUS_INTERFACE_OBJECT_MANAGER,
+ "GetManagedObjects", NULL,
+ get_managed_objects_join_cb,
+ req, l_free);
+}
+
+static void build_element_config(void *a, void *b)
+{
+ struct node_element *ele = a;
+ struct l_dbus_message_builder *builder = b;
+
+ l_debug("Element %u", ele->idx);
+
+ l_dbus_message_builder_enter_struct(builder, "ya(qa{sv})");
+
+ /* Element index */
+ l_dbus_message_builder_append_basic(builder, 'y', &ele->idx);
+
+ l_dbus_message_builder_enter_array(builder, "(qa{sv})");
+
+ /* Iterate over models */
+ l_queue_foreach(ele->models, model_build_config, builder);
+
+ l_dbus_message_builder_leave_array(builder);
+
+ l_dbus_message_builder_leave_struct(builder);
+}
+
+void node_build_attach_reply(struct l_dbus_message *reply, uint64_t token)
+{
+ struct mesh_node *node;
+ struct l_dbus_message_builder *builder;
+
+ node = l_queue_find(nodes, match_token, &token);
+ if (!node)
+ return;
+
+ builder = l_dbus_message_builder_new(reply);
+
+ /* Node object path */
+ l_dbus_message_builder_append_basic(builder, 'o', node->path);
+
+ /* Array of element configurations "a*/
+ l_dbus_message_builder_enter_array(builder, "(ya(qa{sv}))");
+ l_queue_foreach(node->elements, build_element_config, builder);
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+}
+
+static struct l_dbus_message *send_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct mesh_node *node = user_data;
+ const char *sender, *ele_path;
+ struct l_dbus_message_iter iter_data;
+ struct node_element *ele;
+ uint16_t dst, app_idx, src;
+ uint8_t data[MESH_MAX_ACCESS_PAYLOAD];
+ uint32_t len;
+ struct l_dbus_message *reply;
+
+ l_debug("Send");
+
+ sender = l_dbus_message_get_sender(msg);
+
+ if (strcmp(sender, node->owner))
+ return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+ if (!l_dbus_message_get_arguments(msg, "oqqay", &ele_path, &dst,
+ &app_idx, &iter_data))
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+ ele = l_queue_find(node->elements, match_element_path, ele_path);
+ if (!ele)
+ return dbus_error(msg, MESH_ERROR_NOT_FOUND,
+ "Element not found");
+
+ src = node_get_primary(node) + ele->idx;
+
+ len = dbus_get_byte_array(&iter_data, data, L_ARRAY_SIZE(data));
+ if (!len)
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+ "Mesh message is empty");
+
+ if (!mesh_model_send(node, src, dst, app_idx,
+ mesh_net_get_default_ttl(node->net), data, len))
+ return dbus_error(msg, MESH_ERROR_FAILED, NULL);
+
+ reply = l_dbus_message_new_method_return(msg);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static struct l_dbus_message *publish_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct mesh_node *node = user_data;
+ const char *sender, *ele_path;
+ struct l_dbus_message_iter iter_data;
+ uint16_t mod_id, src;
+ struct node_element *ele;
+ uint8_t data[MESH_MAX_ACCESS_PAYLOAD];
+ uint32_t len;
+ struct l_dbus_message *reply;
+ int result;
+
+ l_debug("Publish");
+
+ sender = l_dbus_message_get_sender(msg);
+
+ if (strcmp(sender, node->owner))
+ return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+ if (!l_dbus_message_get_arguments(msg, "oqay", &ele_path, &mod_id,
+ &iter_data))
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+ ele = l_queue_find(node->elements, match_element_path, ele_path);
+ if (!ele)
+ return dbus_error(msg, MESH_ERROR_NOT_FOUND,
+ "Element not found");
+
+ src = node_get_primary(node) + ele->idx;
+
+ len = dbus_get_byte_array(&iter_data, data, L_ARRAY_SIZE(data));
+ if (!len)
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+ "Mesh message is empty");
+
+ result = mesh_model_publish(node, VENDOR_ID_MASK | mod_id, src,
+ mesh_net_get_default_ttl(node->net), data, len);
+
+ if (result != MESH_ERROR_NONE)
+ return dbus_error(msg, result, NULL);
+
+ reply = l_dbus_message_new_method_return(msg);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static struct l_dbus_message *vendor_publish_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct mesh_node *node = user_data;
+ const char *sender, *ele_path;
+ struct l_dbus_message_iter iter_data;
+ uint16_t src;
+ uint16_t model_id, vendor;
+ uint32_t vendor_mod_id;
+ struct node_element *ele;
+ uint8_t data[MESH_MAX_ACCESS_PAYLOAD];
+ uint32_t len;
+ struct l_dbus_message *reply;
+ int result;
+
+ l_debug("Publish");
+
+ sender = l_dbus_message_get_sender(msg);
+
+ if (strcmp(sender, node->owner))
+ return dbus_error(msg, MESH_ERROR_NOT_AUTHORIZED, NULL);
+
+ if (!l_dbus_message_get_arguments(msg, "oqqay", &ele_path, &vendor,
+ &model_id, &iter_data))
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+ ele = l_queue_find(node->elements, match_element_path, ele_path);
+ if (!ele)
+ return dbus_error(msg, MESH_ERROR_NOT_FOUND,
+ "Element not found");
+
+ src = node_get_primary(node) + ele->idx;
+
+ len = dbus_get_byte_array(&iter_data, data, L_ARRAY_SIZE(data));
+ if (!len)
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+ "Mesh message is empty");
+
+ vendor_mod_id = (vendor << 16) | model_id;
+ result = mesh_model_publish(node, vendor_mod_id, src,
+ mesh_net_get_default_ttl(node->net), data, len);
+
+ if (result != MESH_ERROR_NONE)
+ return dbus_error(msg, result, NULL);
+
+ reply = l_dbus_message_new_method_return(msg);
+ l_dbus_message_set_arguments(reply, "");
+
+ return reply;
+}
+
+static void setup_node_interface(struct l_dbus_interface *iface)
+{
+ l_dbus_interface_method(iface, "Send", 0, send_call, "", "oqqay",
+ "element_path", "destination",
+ "key", "data");
+ l_dbus_interface_method(iface, "Publish", 0, publish_call, "", "oqay",
+ "element_path", "model_id", "data");
+ l_dbus_interface_method(iface, "VendorPublish", 0, vendor_publish_call,
+ "", "oqqay", "element_path",
+ "vendor", "model_id", "data");
+
+ /*TODO: Properties */
+}
+
+bool node_dbus_init(struct l_dbus *bus)
+{
+ if (!l_dbus_register_interface(bus, MESH_NODE_INTERFACE,
+ setup_node_interface,
+ NULL, false)) {
+ l_info("Unable to register %s interface", MESH_NODE_INTERFACE);
+ return false;
+ }
+
+ return true;
+}
+
+const char *node_get_owner(struct mesh_node *node)
+{
+ return node->owner;
+}
+
+const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx)
+{
+ struct node_element *ele;
+
+ ele = l_queue_find(node->elements, match_element_idx,
+ L_UINT_TO_PTR(ele_idx));
+
+ if (!ele)
+ return NULL;
+
+ return ele->path;
+}
+
+bool node_add_pending_local(struct mesh_node *node, void *prov_node_info,
+ struct mesh_io *io)
+{
+ struct mesh_prov_node_info *info = prov_node_info;
+ bool kr = !!(info->flags & PROV_FLAG_KR);
+ bool ivu = !!(info->flags & PROV_FLAG_IVU);
+
+ node->net = mesh_net_new(node);
+
+ if (!nodes)
+ nodes = l_queue_new();
+
+ l_queue_push_tail(nodes, node);
+
+ if (!storage_set_iv_index(node->net, info->iv_index, ivu))
+ return false;
+
+ mesh_net_set_iv_index(node->net, info->iv_index, ivu);
+
+ if (!mesh_db_write_uint16_hex(node->jconfig, "unicastAddress",
+ info->unicast))
+ return false;
+
+ node->primary = info->unicast;
+ mesh_net_register_unicast(node->net, info->unicast, node->num_ele);
+
+ memcpy(node->dev_key, info->device_key, 16);
+ if (!mesh_db_write_device_key(node->jconfig, info->device_key))
+ return false;
+
+ if (mesh_net_add_key(node->net, kr, info->net_index,
+ info->net_key) != MESH_STATUS_SUCCESS)
+ return false;
+
+ if (!storage_net_key_add(node->net, info->net_index, info->net_key,
+ kr ? KEY_REFRESH_PHASE_TWO : KEY_REFRESH_PHASE_NONE))
+ return false;
+
+ if (!storage_save_config(node, true, NULL, NULL))
+ return false;
+
+ /* Initialize configuration server model */
+ mesh_config_srv_init(node, PRIMARY_ELE_IDX);
+
+ mesh_net_attach(node->net, io);
+
+ return true;
+}
+
+void node_jconfig_set(struct mesh_node *node, void *jconfig)
+{
+ node->jconfig = jconfig;
+}
+
+void *node_jconfig_get(struct mesh_node *node)
+{
+ return node->jconfig;
+}
+
+void node_cfg_file_set(struct mesh_node *node, char *cfg)
+{
+ node->cfg_file = cfg;
+}
+
+char * node_cfg_file_get(struct mesh_node *node)
+{
+ return node->cfg_file;
+}
+
+struct mesh_net *node_get_net(struct mesh_node *node)
+{
+ return node->net;
+}
diff --git a/mesh/node.h b/mesh/node.h
index f417fe503..196b54c4d 100644
--- a/mesh/node.h
+++ b/mesh/node.h
@@ -18,35 +18,40 @@
*
*/
-#include "mesh/mesh-db.h"
-
struct mesh_net;
struct mesh_node;
+struct mesh_io;
+struct mesh_agent;
/* To prevent local node JSON cache thrashing, minimum update times */
#define MIN_SEQ_TRIGGER 32
#define MIN_SEQ_CACHE (2*MIN_SEQ_TRIGGER)
#define MIN_SEQ_CACHE_TIME (5*60)
+typedef void (*node_attach_ready_func_t) (int status, char *node_path,
+ uint64_t token);
+
+typedef void (*node_join_ready_func_t) (struct mesh_node *node,
+ struct mesh_agent *agent);
+
struct mesh_node *node_new(void);
void node_free(struct mesh_node *node);
+void node_join(const char *app_path, const char *sender, const uint8_t *uuid,
+ node_join_ready_func_t cb);
uint8_t *node_uuid_get(struct mesh_node *node);
+struct mesh_net *node_get_net(struct mesh_node *node);
struct mesh_node *node_find_by_addr(uint16_t addr);
struct mesh_node *node_find_by_uuid(uint8_t uuid[16]);
bool node_is_provisioned(struct mesh_node *node);
bool node_app_key_delete(struct mesh_net *net, uint16_t addr,
uint16_t net_idx, uint16_t idx);
-bool node_net_key_delete(struct mesh_node *node, uint16_t index);
-bool node_set_primary(struct mesh_node *node, uint16_t unicast);
uint16_t node_get_primary(struct mesh_node *node);
uint16_t node_get_primary_net_idx(struct mesh_node *node);
-bool node_set_device_key(struct mesh_node *node, uint8_t key[16]);
+void node_set_device_key(struct mesh_node *node, uint8_t key[16]);
const uint8_t *node_get_device_key(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);
bool node_parse_composition(struct mesh_node *node, uint8_t *buf, uint16_t len);
-struct l_queue *node_get_net_keys(struct mesh_node *node);
-struct l_queue *node_get_app_keys(struct mesh_node *node);
bool node_add_binding(struct mesh_node *node, uint8_t ele_idx,
uint32_t model_id, uint16_t app_idx);
bool node_del_binding(struct mesh_node *node, uint8_t ele_idx,
@@ -58,12 +63,8 @@ uint32_t node_get_sequence_number(struct mesh_node *node);
int node_get_element_idx(struct mesh_node *node, uint16_t ele_addr);
struct l_queue *node_get_element_models(struct mesh_node *node, uint8_t ele_idx,
int *status);
-struct mesh_model *node_get_model(struct mesh_node *node, uint8_t ele_idx,
- uint32_t id, int *status);
uint16_t node_get_crpl(struct mesh_node *node);
-struct mesh_node *node_create_from_storage(struct mesh_net *net,
- struct mesh_db_node *db_node,
- bool local);
+bool node_init_from_storage(struct mesh_node *node, void *data);
uint16_t node_generate_comp(struct mesh_node *node, uint8_t *buf, uint16_t sz);
uint8_t node_lpn_mode_get(struct mesh_node *node);
bool node_relay_mode_set(struct mesh_node *node, bool enable, uint8_t cnt,
@@ -77,4 +78,19 @@ uint8_t node_beacon_mode_get(struct mesh_node *node);
bool node_friend_mode_set(struct mesh_node *node, bool enable);
uint8_t node_friend_mode_get(struct mesh_node *node);
uint32_t node_seq_cache(struct mesh_node *node);
-void node_cleanup(struct mesh_net *net);
+const char *node_get_element_path(struct mesh_node *node, uint8_t ele_idx);
+const char *node_get_owner(struct mesh_node *node);
+bool node_add_pending_local(struct mesh_node *node, void *info,
+ struct mesh_io *io);
+void node_attach_io(struct mesh_io *io);
+int node_attach(const char *app_path, const char *sender, uint64_t token,
+ node_attach_ready_func_t cb);
+void node_build_attach_reply(struct l_dbus_message *reply, uint64_t token);
+void node_id_set(struct mesh_node *node, uint16_t node_id);
+bool node_dbus_init(struct l_dbus *bus);
+void node_cleanup(void *node);
+void node_cleanup_all(void);
+void node_jconfig_set(struct mesh_node *node, void *jconfig);
+void *node_jconfig_get(struct mesh_node *node);
+void node_cfg_file_set(struct mesh_node *node, char *cfg);
+char *node_cfg_file_get(struct mesh_node *node);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 07/30] mesh: Rewite Network layer for multiple nodes
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (5 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 06/30] mesh: Rewrite Node handling for multiple nodes Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 08/30] mesh: Direction agnostic PB-Adv implimentation Brian Gix
` (22 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/net.c | 293 ++++++++++++++++---------------------------------------------
mesh/net.h | 31 ++-----
2 files changed, 83 insertions(+), 241 deletions(-)
diff --git a/mesh/net.c b/mesh/net.c
index 97b6f5b16..b47df7c04 100644
--- a/mesh/net.c
+++ b/mesh/net.c
@@ -30,7 +30,6 @@
#include "mesh/mesh-defs.h"
#include "mesh/util.h"
-#include "mesh/display.h"
#include "mesh/crypto.h"
#include "mesh/net_keys.h"
#include "mesh/mesh.h"
@@ -112,12 +111,9 @@ struct mesh_subnet {
};
struct mesh_net {
- int ref_count;
struct mesh_io *io;
- struct mesh_node *local_node;
+ struct mesh_node *node;
struct mesh_prov *prov;
- void *jconfig_local;
- const char *cfg_file;
struct l_queue *app_keys;
unsigned int pkt_id;
unsigned int bea_id;
@@ -129,7 +125,6 @@ struct mesh_net {
bool beacon_enable;
bool proxy_enable;
bool provisioner;
- bool provisioned;
bool friend_seq;
struct l_timeout *iv_update_timeout;
enum _iv_upd_state iv_upd_state;
@@ -139,7 +134,6 @@ struct mesh_net {
uint32_t iv_index;
uint32_t seq_num;
uint32_t cached_seq_num;
- uint16_t crpl;
uint16_t src_addr;
uint16_t last_addr;
uint16_t friend_addr;
@@ -253,6 +247,8 @@ struct net_decode {
bool proxy;
};
+static struct l_queue *nets;
+
static inline struct mesh_subnet *get_primary_subnet(struct mesh_net *net)
{
return l_queue_peek_head(net->subnets);
@@ -499,8 +495,8 @@ uint32_t mesh_net_next_seq_num(struct mesh_net *net)
/* Periodically store advanced sequence number */
if (net->seq_num + MIN_SEQ_TRIGGER >= net->cached_seq_num) {
net->cached_seq_num = net->seq_num +
- node_seq_cache(net->local_node);
- node_set_sequence_number(net->local_node, net->cached_seq_num);
+ node_seq_cache(net->node);
+ node_set_sequence_number(net->node, net->cached_seq_num);
}
return seq;
@@ -647,15 +643,13 @@ static void start_network_beacon(void *a, void *b)
network_beacon_timeout, subnet, NULL);
}
-struct mesh_net *mesh_net_new(uint16_t index)
+struct mesh_net *mesh_net_new(struct mesh_node *node)
{
struct mesh_net *net;
net = l_new(struct mesh_net, 1);
- if (!net)
- return NULL;
-
+ net->node = node;
net->pkt_id = 0;
net->bea_id = 0;
net->key_id_next = 0;
@@ -689,27 +683,17 @@ struct mesh_net *mesh_net_new(uint16_t index)
memset(&net->heartbeat, 0, sizeof(net->heartbeat));
- return mesh_net_ref(net);
-}
-
-struct mesh_net *mesh_net_ref(struct mesh_net *net)
-{
- if (!net)
- return NULL;
-
- __sync_fetch_and_add(&net->ref_count, 1);
+ if (!nets)
+ nets = l_queue_new();
return net;
}
-void mesh_net_unref(struct mesh_net *net)
+void mesh_net_free(struct mesh_net *net)
{
if (!net)
return;
- if (__sync_sub_and_fetch(&net->ref_count, 1))
- return;
-
l_queue_destroy(net->subnets, subnet_free);
l_queue_destroy(net->fast_cache, mesh_msg_free);
l_queue_destroy(net->msg_cache, mesh_msg_free);
@@ -773,7 +757,6 @@ bool mesh_net_register_unicast(struct mesh_net *net,
if (!net || !IS_UNICAST(address) || !num_ele)
return false;
- l_info("mesh_net_set_address: 0x%x", address);
net->src_addr = address;
net->last_addr = address + num_ele - 1;
if (net->last_addr < net->src_addr)
@@ -971,7 +954,7 @@ int mesh_net_del_key(struct mesh_net *net, uint16_t idx)
l_queue_remove(net->subnets, subnet);
subnet_free(subnet);
- if (!storage_local_net_key_del(net, idx))
+ if (!storage_net_key_del(net, idx))
return MESH_STATUS_STORAGE_FAIL;
return MESH_STATUS_SUCCESS;
@@ -991,7 +974,7 @@ int mesh_net_add_key(struct mesh_net *net, bool update, uint16_t idx,
l_info("Start key refresh");
status = mesh_net_kr_phase_one(net, idx, value);
if (status == MESH_STATUS_SUCCESS &&
- !storage_local_net_key_add(net, idx,
+ !storage_net_key_add(net, idx,
value, KEY_REFRESH_PHASE_ONE))
return MESH_STATUS_STORAGE_FAIL;
} else
@@ -1021,7 +1004,7 @@ int mesh_net_add_key(struct mesh_net *net, bool update, uint16_t idx,
return MESH_STATUS_INSUFF_RESOURCES;
}
- if (!storage_local_net_key_add(net, idx, value,
+ if (!storage_net_key_add(net, idx, value,
KEY_REFRESH_PHASE_NONE)) {
l_queue_remove(net->subnets, subnet);
subnet_free(subnet);
@@ -1204,14 +1187,6 @@ static bool match_msg_timeout(const void *a, const void *b)
return sar->msg_timeout == msg_timeout;
}
-static bool match_sar_id(const void *a, const void *b)
-{
- const struct mesh_sar *sar = a;
- unsigned int id = L_PTR_TO_UINT(b);
-
- return sar->id == id;
-}
-
static bool match_seg_timeout(const void *a, const void *b)
{
const struct mesh_sar *sar = a;
@@ -1813,7 +1788,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd,
}
not_for_friend:
- return mesh_model_rx(net, szmic, seqAuth, seq, iv_index,
+ return mesh_model_rx(net->node, szmic, seqAuth, seq, iv_index,
ttl, src, dst, key_id, data, size);
}
@@ -2511,22 +2486,40 @@ static void packet_received(void *user_data, const void *data, uint8_t size,
send_relay_pkt(net, packet, size + 1);
}
+struct net_queue_data {
+ struct mesh_io_recv_info *info;
+ const uint8_t *data;
+ uint16_t len;
+};
+
+static void net_rx(void *net_ptr, void *user_data)
+{
+ struct net_queue_data *data = user_data;
+ struct mesh_net *net = net_ptr;
+ int8_t rssi = 0;
+
+ if (data->info) {
+ net->instant = data->info->instant;
+ net->chan = data->info->chan;
+ rssi = data->info->rssi;
+ }
+
+ packet_received(net, data->data, data->len, rssi);
+}
+
static void net_msg_recv(void *user_data, struct mesh_io_recv_info *info,
const uint8_t *data, uint16_t len)
{
- struct mesh_net *net = user_data;
- int8_t rssi = 0;
+ struct net_queue_data net_data = {
+ .info = info,
+ .data = data + 1,
+ .len = len - 1,
+ };
- if (len <= 2 || !net)
+ if (len <= 2)
return;
- if (info) {
- net->instant = info->instant;
- net->chan = info->chan;
- rssi = info->rssi;
- }
-
- packet_received(user_data, data + 1, len - 1, rssi);
+ l_queue_foreach(nets, net_rx, &net_data);
}
static void set_network_beacon(void *a, void *b)
@@ -2653,7 +2646,7 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
net->iv_upd_state = IV_UPD_NORMAL;
}
- storage_local_set_iv_index(net, iv_index, net->iv_upd_state);
+ storage_set_iv_index(net, iv_index, net->iv_upd_state);
/* Figure out the key refresh phase */
if (kr_transition) {
@@ -2675,7 +2668,7 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
net->iv_upd_state = IV_UPD_UPDATING;
net->iv_update_timeout = l_timeout_create(IV_IDX_UPD_MIN,
iv_upd_to, net, NULL);
- storage_local_set_iv_index(net, iv_index, net->iv_upd_state);
+ storage_set_iv_index(net, iv_index, net->iv_upd_state);
} else if (iv_update && iv_index != net->iv_index) {
l_error("Update attempted too soon (iv idx already updated)");
return;
@@ -2688,7 +2681,7 @@ static void update_iv_kr_state(struct mesh_subnet *subnet, uint32_t iv_index,
if (iv_index > net->iv_index) {
l_queue_clear(net->msg_cache, mesh_msg_free);
net->iv_index = iv_index;
- storage_local_set_iv_index(net, iv_index, net->iv_upd_state);
+ storage_set_iv_index(net, iv_index, net->iv_upd_state);
}
/* Figure out the key refresh phase */
@@ -2915,34 +2908,37 @@ bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable)
return true;
}
+static bool is_this_net(const void *a, const void *b)
+{
+ return a == b;
+}
+
bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io)
{
+ bool first;
+
if (!net)
return false;
- net->io = io;
- if (net->provisioned) {
+ first = l_queue_isempty(nets);
+ if (first) {
+ if (!nets)
+ nets = l_queue_new();
+ l_info("Register io cb");
mesh_io_register_recv_cb(io, MESH_IO_FILTER_BEACON,
beacon_recv, net);
mesh_io_register_recv_cb(io, MESH_IO_FILTER_NET,
- net_msg_recv, net);
+ net_msg_recv, NULL);
l_queue_foreach(net->subnets, start_network_beacon, net);
+ }
- } else {
- uint8_t *uuid = node_uuid_get(net->local_node);
-
- if (!uuid)
- return false;
+ if (l_queue_find(nets, is_this_net, net))
+ return false;
- mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
- mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_NET);
+ l_queue_push_head(nets, net);
- mesh_prov_listen(net, uuid, (uint8_t *) &net->prov_caps,
- acceptor_prov_open,
- acceptor_prov_close,
- acceptor_prov_receive, net);
- }
+ net->io = io;
return true;
}
@@ -2952,10 +2948,10 @@ struct mesh_io *mesh_net_detach(struct mesh_net *net)
struct mesh_io *io;
uint8_t type = 0;
- if (!net)
+ if (!net || !net->io)
return NULL;
- io = net->io;
+ io = net->io;
mesh_io_send_cancel(net->io, &type, 1);
mesh_io_deregister_recv_cb(io, MESH_IO_FILTER_BEACON);
@@ -2975,7 +2971,7 @@ bool mesh_net_iv_index_update(struct mesh_net *net)
mesh_net_flush_msg_queues(net);
net->iv_upd_state = IV_UPD_UPDATING;
net->iv_index++;
- if (!storage_local_set_iv_index(net, net->iv_index, IV_UPD_UPDATING))
+ if (!storage_set_iv_index(net, net->iv_index, IV_UPD_UPDATING))
return false;
l_queue_foreach(net->subnets, set_network_beacon, net);
@@ -3241,28 +3237,25 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id,
l_free(str);
}
-unsigned int mesh_net_app_send(struct mesh_net *net, bool frnd_cred,
- uint16_t src, uint16_t dst,
- uint8_t key_id, uint8_t ttl,
- uint32_t seq, uint32_t iv_index,
- bool szmic,
+bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
+ uint16_t dst, uint8_t key_id, uint8_t ttl,
+ uint32_t seq, uint32_t iv_index, bool szmic,
const void *msg, uint16_t msg_len,
mesh_net_status_func_t status_func,
void *user_data)
{
struct mesh_sar *payload = NULL;
uint8_t seg, seg_max;
- unsigned int ret = 0;
bool result;
if (!net || msg_len > 384)
- return 0;
+ return false;
if (!src)
src = net->src_addr;
if (!src || !dst)
- return 0;
+ return false;
if (ttl == 0xff)
ttl = net->default_ttl;
@@ -3287,7 +3280,7 @@ unsigned int mesh_net_app_send(struct mesh_net *net, bool frnd_cred,
/* Adjust our seq_num for "virtual" delivery */
net->seq_num += seg_max;
mesh_net_next_seq_num(net);
- return 0;
+ return true;
}
/* If Segmented, Cancel any OB segmented message to same DST */
@@ -3337,29 +3330,13 @@ unsigned int mesh_net_app_send(struct mesh_net *net, bool frnd_cred,
l_timeout_create(MSG_TO, outmsg_to, net, NULL);
payload->status_func = status_func;
payload->user_data = user_data;
- ret = payload->id = ++net->sar_id_next;
+ payload->id = ++net->sar_id_next;
} else
mesh_sar_free(payload);
- return ret;
-}
-
-void mesh_net_app_send_cancel(struct mesh_net *net, unsigned int id)
-{
- struct mesh_sar *sar = l_queue_remove_if(net->sar_out, match_sar_id,
- L_UINT_TO_PTR(id));
-
- if (sar) {
- l_info("Canceling OB %d", id);
- if (sar->status_func)
- sar->status_func(sar->remote, 2,
- sar->buf, sar->len - 4,
- sar->user_data);
- }
- mesh_sar_free(sar);
+ return result;
}
-/* TODO: add net key index */
void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id,
uint32_t iv_index,
uint8_t ttl,
@@ -3768,40 +3745,9 @@ uint32_t mesh_net_friend_timeout(struct mesh_net *net, uint16_t addr)
return frnd->poll_timeout;
}
-bool mesh_net_local_node_set(struct mesh_net *net, struct mesh_node *node,
- bool provisioner)
+struct mesh_node *mesh_net_node_get(struct mesh_net *net)
{
- if (net->local_node) {
- l_info("Local node already registered");
- return false;
- }
-
- net->local_node = node;
- net->provisioner = provisioner;
-
- return true;
-}
-
-struct mesh_node *mesh_net_local_node_get(struct mesh_net *net)
-{
- return net->local_node;
-}
-
-bool mesh_net_set_crpl(struct mesh_net *net, uint16_t crpl)
-{
- if (!net)
- return false;
-
- net->crpl = crpl;
- return true;
-}
-
-uint16_t mesh_net_get_crpl(struct mesh_net *net)
-{
- if (!net)
- return 0;
-
- return net->crpl;
+ return net->node;
}
struct l_queue *mesh_net_get_app_keys(struct mesh_net *net)
@@ -3824,41 +3770,6 @@ bool mesh_net_have_key(struct mesh_net *net, uint16_t idx)
L_UINT_TO_PTR(idx)) != NULL);
}
-bool mesh_net_jconfig_set(struct mesh_net *net, void *jconfig)
-{
- if (!net)
- return false;
-
- net->jconfig_local = jconfig;
- return true;
-}
-
-void *mesh_net_jconfig_get(struct mesh_net *net)
-{
- if (!net)
- return NULL;
-
- return net->jconfig_local;
-}
-
-bool mesh_net_cfg_file_set(struct mesh_net *net, const char *cfg)
-{
- if (!net)
- return false;
-
- net->cfg_file = cfg;
- return true;
-}
-
-bool mesh_net_cfg_file_get(struct mesh_net *net, const char **cfg)
-{
- if (!net)
- return false;
-
- *cfg = net->cfg_file;
- return true;
-}
-
bool mesh_net_is_local_address(struct mesh_net *net, uint16_t addr)
{
if (!net)
@@ -3919,55 +3830,3 @@ void mesh_net_set_prov(struct mesh_net *net, struct mesh_prov *prov)
net->prov = prov;
}
-bool mesh_net_provisioned_new(struct mesh_net *net, uint8_t device_key[16],
- uint16_t net_idx, uint8_t net_key[16],
- uint16_t unicast, uint16_t snb_flags,
- uint32_t iv_index, mesh_status_func_t cb,
- void *user_data)
-{
- if (net->provisioned || !net->local_node)
- return false;
-
- if (!node_set_primary(net->local_node, unicast) ||
- !(mesh_net_register_unicast(net, unicast,
- mesh_net_get_num_ele(net))))
- return false;
-
- if (!node_set_device_key(net->local_node, device_key))
- return false;
-
- net->iv_index = iv_index;
- net->iv_update = ((snb_flags & 0x02) != 0);
- if (!storage_local_set_iv_index(net, iv_index, net->iv_update))
- return false;
-
- if (mesh_net_add_key(net, false, net_idx, net_key) !=
- MESH_STATUS_SUCCESS)
- return false;
-
- if ((snb_flags & 0x01) &&
- (mesh_net_add_key(net, true, net_idx, net_key) !=
- MESH_STATUS_SUCCESS)) {
- l_queue_clear(net->subnets, l_free);
- return false;
- }
-
- return storage_save_new_config(net, net->cfg_file, cb, user_data);
-
-}
-
-void mesh_net_provisioned_set(struct mesh_net *net, bool provisioned)
-{
- if (!net)
- return;
-
- net->provisioned = provisioned;
-}
-
-bool mesh_net_provisioned_get(struct mesh_net *net)
-{
- if (!net)
- return false;
-
- return net->provisioned;
-}
diff --git a/mesh/net.h b/mesh/net.h
index b8eb0699d..c63ea59ee 100644
--- a/mesh/net.h
+++ b/mesh/net.h
@@ -259,9 +259,8 @@ typedef void (*mesh_net_status_func_t)(uint16_t remote, uint8_t status,
void *data, uint16_t size,
void *user_data);
-struct mesh_net *mesh_net_new(uint16_t index);
-struct mesh_net *mesh_net_ref(struct mesh_net *net);
-void mesh_net_unref(struct mesh_net *net);
+struct mesh_net *mesh_net_new(struct mesh_node *node);
+void mesh_net_free(struct mesh_net *net);
void mesh_net_flush_msg_queues(struct mesh_net *net);
void mesh_net_set_iv_index(struct mesh_net *net, uint32_t index, bool update);
bool mesh_net_iv_index_update(struct mesh_net *net);
@@ -301,13 +300,12 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id,
uint32_t seq, uint16_t src, uint16_t dst,
const uint8_t *msg, uint16_t msg_len);
-unsigned int mesh_net_app_send(struct mesh_net *net, bool frnd_cred,
- uint16_t src, uint16_t dst, uint8_t key_id,
- uint8_t ttl, uint32_t seq, uint32_t iv_index,
- bool szmic, const void *msg, uint16_t msg_len,
+bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src,
+ uint16_t dst, uint8_t key_id, uint8_t ttl,
+ uint32_t seq, uint32_t iv_index, bool szmic,
+ const void *msg, uint16_t msg_len,
mesh_net_status_func_t status_func,
void *user_data);
-void mesh_net_app_send_cancel(struct mesh_net *net, unsigned int id);
void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id,
uint32_t iv_index, uint8_t ttl, uint32_t seq,
uint16_t src, uint16_t dst, bool rly,
@@ -363,16 +361,8 @@ void mesh_net_sub_list_add(struct mesh_net *net, uint16_t addr);
void mesh_net_sub_list_del(struct mesh_net *net, uint16_t addr);
uint32_t mesh_net_friend_timeout(struct mesh_net *net, uint16_t addr);
struct mesh_io *mesh_net_get_io(struct mesh_net *net);
-bool mesh_net_local_node_set(struct mesh_net *net, struct mesh_node *node,
- bool provisioner);
-struct mesh_node *mesh_net_local_node_get(struct mesh_net *net);
-bool mesh_net_set_crpl(struct mesh_net *net, uint16_t crpl);
-uint16_t mesh_net_get_crpl(struct mesh_net *net);
+struct mesh_node *mesh_net_node_get(struct mesh_net *net);
bool mesh_net_have_key(struct mesh_net *net, uint16_t net_idx);
-bool mesh_net_jconfig_set(struct mesh_net *net, void *jconfig);
-void *mesh_net_jconfig_get(struct mesh_net *net);
-bool mesh_net_cfg_file_set(struct mesh_net *net, const char *cfg);
-bool mesh_net_cfg_file_get(struct mesh_net *net, const char **cfg);
bool mesh_net_is_local_address(struct mesh_net *net, uint16_t addr);
void mesh_net_set_window_accuracy(struct mesh_net *net, uint8_t accuracy);
void mesh_net_transmit_params_set(struct mesh_net *net, uint8_t count,
@@ -381,10 +371,3 @@ void mesh_net_transmit_params_get(struct mesh_net *net, uint8_t *count,
uint16_t *interval);
struct mesh_prov *mesh_net_get_prov(struct mesh_net *net);
void mesh_net_set_prov(struct mesh_net *net, struct mesh_prov *prov);
-void mesh_net_provisioned_set(struct mesh_net *net, bool provisioned);
-bool mesh_net_provisioned_get(struct mesh_net *net);
-bool mesh_net_provisioned_new(struct mesh_net *net, uint8_t device_key[16],
- uint16_t net_idx, uint8_t net_key[16],
- uint16_t unicast, uint16_t snb_flags,
- uint32_t iv_index, mesh_status_func_t cb,
- void *user_data);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 08/30] mesh: Direction agnostic PB-Adv implimentation
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (6 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 07/30] mesh: Rewite Network layer " Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 09/30] mesh: Acceptor side provisioning implimentation Brian Gix
` (21 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/pb-adv.c | 444 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
mesh/pb-adv.h | 23 +++
2 files changed, 467 insertions(+)
create mode 100644 mesh/pb-adv.c
create mode 100644 mesh/pb-adv.h
diff --git a/mesh/pb-adv.c b/mesh/pb-adv.c
new file mode 100644
index 000000000..57647e184
--- /dev/null
+++ b/mesh/pb-adv.c
@@ -0,0 +1,444 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2018 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/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <time.h>
+#include <ell/ell.h>
+
+#include "mesh/mesh-defs.h"
+#include "src/shared/ecc.h"
+
+#include "mesh/util.h"
+#include "mesh/net_keys.h"
+#include "mesh/crypto.h"
+#include "mesh/net.h"
+#include "mesh/mesh-io.h"
+#include "mesh/mesh.h"
+#include "mesh/prov.h"
+#include "mesh/provision.h"
+#include "mesh/pb-adv.h"
+
+
+struct pb_adv_session {
+ 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 l_timeout *tx_timeout;
+ uint32_t conn_id;
+ uint16_t exp_len;
+ uint8_t exp_fcs;
+ uint8_t exp_segs;
+ uint8_t got_segs;
+ uint8_t msg_num;
+ uint8_t local_acked;
+ uint8_t local_msg_num;
+ uint8_t peer_msg_num;
+ uint8_t last_peer_msg_num;
+ uint8_t sar[80];
+ uint8_t uuid[16];
+ bool initiator;
+ bool opened;
+ void *user_data;
+};
+
+#define PB_ADV_ACK 0x01
+#define PB_ADV_OPEN_REQ 0x03
+#define PB_ADV_OPEN_CFM 0x07
+#define PB_ADV_CLOSE 0x0B
+
+#define PB_ADV_MTU 24
+
+static struct pb_adv_session *pb_session = NULL;
+
+static void send_adv_segs(struct pb_adv_session *session, const uint8_t *data,
+ uint16_t size)
+{
+ uint16_t init_size;
+ uint8_t buf[PB_ADV_MTU + 6] = { MESH_AD_TYPE_PROVISION };
+ uint8_t max_seg;
+ uint8_t consumed;
+ int i;
+
+ if (!size)
+ return;
+
+ mesh_send_cancel(buf, 1);
+
+ l_put_be32(session->conn_id, buf + 1);
+ buf[1 + 4] = ++session->local_msg_num;
+
+ if (size > PB_ADV_MTU - 4) {
+ max_seg = 1 +
+ (((size - (PB_ADV_MTU - 4)) - 1) / (PB_ADV_MTU - 1));
+ init_size = PB_ADV_MTU - 4;
+ } else {
+ max_seg = 0;
+ init_size = size;
+ }
+
+ /* print_packet("FULL-TX", data, size); */
+
+ l_debug("Sending %u fragments for %u octets", max_seg + 1, size);
+
+ buf[6] = max_seg << 2;
+ l_put_be16(size, buf + 7);
+ buf[9] = mesh_crypto_compute_fcs(data, size);
+ memcpy(buf + 10, data, init_size);
+
+ l_debug("max_seg: %2.2x", max_seg);
+ l_debug("size: %2.2x, CRC: %2.2x", size, buf[9]);
+ /* print_packet("PB-TX", buf + 1, init_size + 9); */
+ mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 50, buf, init_size + 10);
+
+ consumed = init_size;
+
+ for (i = 1; i <= max_seg; i++) {
+ uint8_t seg_size; /* Amount of payload data being sent */
+
+ if (size - consumed > PB_ADV_MTU - 1)
+ seg_size = PB_ADV_MTU - 1;
+ else
+ seg_size = size - consumed;
+
+ buf[6] = (i << 2) | 0x02;
+ memcpy(buf + 7, data + consumed, seg_size);
+
+ /* print_packet("PB-TX", buf + 1, seg_size + 6); */
+
+ mesh_send_pkt(MESH_IO_TX_COUNT_UNLIMITED, 50,
+ buf, seg_size + 7);
+
+ consumed += seg_size;
+ }
+}
+
+static void tx_timeout(struct l_timeout *timeout, void *user_data)
+{
+ struct pb_adv_session *session = user_data;
+ uint8_t cancel[] = { MESH_AD_TYPE_PROVISION };
+ mesh_prov_close_func_t cb;
+
+ if (!session || pb_session != session)
+ return;
+
+ l_timeout_remove(session->tx_timeout);
+ session->tx_timeout = NULL;
+
+ mesh_send_cancel(cancel, sizeof(cancel));
+
+ l_info("TX timeout");
+ cb = pb_session->close_cb;
+ user_data = pb_session->user_data;
+ l_free(pb_session);
+ pb_session = NULL;
+ cb(user_data, 1);
+}
+
+static void pb_adv_tx(void *user_data, uint8_t *data, uint16_t len)
+{
+ struct pb_adv_session *session = user_data;
+
+ if (!session || pb_session != session)
+ return;
+
+ l_timeout_remove(session->tx_timeout);
+ session->tx_timeout = l_timeout_create(30, tx_timeout, session, NULL);
+
+ send_adv_segs(session, data, len);
+}
+
+static void send_open_cfm(struct pb_adv_session *session)
+{
+ uint8_t open_cfm[7] = { MESH_AD_TYPE_PROVISION };
+
+ l_put_be32(session->conn_id, open_cfm + 1);
+ open_cfm[1 + 4] = 0;
+ open_cfm[1 + 4 + 1] = 0x07; /* OPEN_CFM */
+
+ /* print_packet("PB-TX", open_cfm + 1, sizeof(open_cfm) - 1); */
+
+ mesh_send_cancel(open_cfm, 1);
+ mesh_send_pkt(5, 100, open_cfm, sizeof(open_cfm));
+}
+
+static void send_ack(struct pb_adv_session *session, uint8_t msg_num)
+{
+ uint8_t ack[7] = { MESH_AD_TYPE_PROVISION };
+
+ l_put_be32(session->conn_id, ack + 1);
+ ack[1 + 4] = msg_num;
+ ack[1 + 4 + 1] = 0x01; /* ACK */
+
+ /* print_packet("ADV-ACK", ack + 1, sizeof(ack) - 1); */
+ mesh_send_pkt(1, 100, ack, sizeof(ack));
+}
+
+static void send_close_ind(struct pb_adv_session *session, uint8_t reason)
+{
+ uint8_t close_ind[8] = { MESH_AD_TYPE_PROVISION };
+
+ if (!pb_session || pb_session->user_data != session)
+ return;
+
+ l_put_be32(session->conn_id, close_ind + 1);
+ close_ind[5] = 0;
+ close_ind[6] = PB_ADV_CLOSE; /* CLOSE_IND */
+ close_ind[7] = reason;
+
+ mesh_send_cancel(close_ind, 1);
+ mesh_send_pkt(5, 100, close_ind, sizeof(close_ind));
+}
+
+static void pb_adv_packet(void *user_data, const uint8_t *pkt, uint16_t len)
+{
+ struct pb_adv_session *session = user_data;
+ uint32_t conn_id;
+ size_t offset;
+ uint8_t msg_num;
+ uint8_t type;
+ bool first;
+
+ if (!session || pb_session != session)
+ return;
+
+ conn_id = l_get_be32(pkt + 1);
+ type = l_get_u8(pkt + 6);
+
+ /* Validate new or existing Connection ID */
+ if (session->conn_id) {
+ if (session->conn_id != conn_id)
+ return;
+ } else if (type != 0x03)
+ return;
+ else if (!conn_id)
+ return;
+
+ msg_num = l_get_u8(pkt + 5);
+ pkt += 7;
+ len -= 7;
+
+ switch (type) {
+ case PB_ADV_OPEN_CFM:
+ /*
+ * Ignore if:
+ * 1. We are acceptor
+ * 2. We are already provisioning on different conn_id
+ */
+
+ if (!session->initiator)
+ return;
+
+ first = !session->opened;
+ session->opened = true;
+
+ /* Only call Open callback once */
+ if (first) {
+ l_debug("PB-ADV open confirmed");
+ session->open_cb(session->user_data, pb_adv_tx,
+ session, PB_ADV);
+ }
+ return;
+
+ case PB_ADV_OPEN_REQ:
+ /*
+ * Ignore if:
+ * 1. We are initiator
+ * 2. Open request not addressed to us
+ * 3. We are already provisioning on different conn_id
+ */
+
+ if (session->initiator)
+ return;
+
+ if (memcmp(pkt, session->uuid, 16))
+ return;
+
+ first = !session->conn_id;
+ session->conn_id = conn_id;
+ session->last_peer_msg_num = 0xFF;
+ session->local_acked = 0xFF;
+ session->peer_msg_num = 0x00;
+ session->local_msg_num = 0x7F;
+ session->opened = true;
+
+ /* Only call Open callback once */
+ if (first) {
+ l_debug("PB-ADV open requested");
+ session->open_cb(session->user_data, pb_adv_tx,
+ session, PB_ADV);
+ }
+
+ /* Send CFM once per received request */
+ send_open_cfm(session);
+ break;
+
+ case PB_ADV_CLOSE:
+ l_timeout_remove(session->tx_timeout);
+ l_debug("Link closed notification: %2.2x", pkt[0]);
+ /* Wrap callback for pre-cleaning */
+ if (true) {
+ mesh_prov_close_func_t cb = session->close_cb;
+ void *user_data = session->user_data;
+
+ l_free(session);
+ pb_session = NULL;
+ cb(user_data, pkt[0]);
+ }
+ break;
+
+ case PB_ADV_ACK:
+ if (!session->opened)
+ return;
+
+ if (msg_num != session->local_msg_num)
+ return;
+
+ if (session->local_acked > msg_num)
+ return;
+
+ l_debug("Got ACK %d", msg_num);
+ session->local_acked = msg_num;
+ session->ack_cb(session->user_data, msg_num);
+ break;
+
+ default: /* DATA SEGMENT */
+ if (!session->opened)
+ return;
+
+ if (msg_num == session->last_peer_msg_num) {
+ send_ack(session, msg_num);
+ return;
+ }
+
+ switch(type & 0x03) {
+ case 0x00:
+ session->peer_msg_num = msg_num;
+ session->exp_len = l_get_be16(pkt);
+
+ l_debug("PB-ADV start with %u fragments, %d octets",
+ type >> 2, session->exp_len);
+
+ if (session->exp_len > sizeof(session->sar)) {
+ l_debug("Incoming length exceeded: %d",
+ session->exp_len);
+ return;
+ }
+
+ session->exp_fcs = l_get_u8(pkt + 2);
+ session->exp_segs = 0xff >> (7 - (type >> 2));
+
+ /* Save first segment */
+ memcpy(session->sar, pkt + 3, len - 3);
+ session->got_segs |= 1;
+ break;
+
+ case 0x02:
+ session->peer_msg_num = msg_num;
+ offset = 20 + (((type >> 2) - 1) * 23);
+
+ if (offset + len - 3 > sizeof(session->sar)) {
+ l_debug("Length exceeded: %d",
+ session->exp_len);
+ return;
+ }
+
+ l_debug("Processing fragment %u", type >> 2);
+ memcpy(session->sar + offset, pkt, len);
+ session->got_segs |= 1 << (type >> 2);
+ break;
+
+ default:
+ /* Malformed or unrecognized */
+ return;
+ }
+
+ if (session->got_segs != session->exp_segs)
+ return;
+
+ /* Validate RXed packet and pass up to Provisioning */
+ if (!mesh_crypto_check_fcs(session->sar,
+ session->exp_len,
+ session->exp_fcs)) {
+
+ /* This can be a false negative if first
+ * segment missed, and can almost always
+ * be ignored.
+ */
+
+ l_debug("Invalid FCS");
+ return;
+ }
+
+ if (session->last_peer_msg_num != session->peer_msg_num) {
+ session->got_segs = 0;
+ session->rx_cb(session->user_data, session->sar,
+ session->exp_len);
+ }
+
+ session->last_peer_msg_num = session->peer_msg_num;
+ send_ack(session, session->last_peer_msg_num);
+ }
+}
+
+bool pb_adv_reg(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)
+{
+ if (pb_session)
+ return false;
+
+ pb_session = l_new(struct pb_adv_session, 1);
+ pb_session->open_cb = open_cb;
+ pb_session->close_cb = close_cb;
+ pb_session->rx_cb = rx_cb;
+ pb_session->ack_cb = ack_cb;
+ pb_session->user_data = user_data;
+ memcpy(pb_session->uuid, uuid, 16);
+
+ /* TODO: register PB AD type and Start Beaconing ? */
+ mesh_reg_prov_rx(pb_adv_packet, pb_session);
+
+ return true;
+}
+
+void pb_adv_unreg(void *user_data)
+{
+ if (!pb_session || pb_session->user_data != user_data)
+ return;
+
+ l_timeout_remove(pb_session->tx_timeout);
+ send_close_ind(pb_session, 0);
+ l_free(pb_session);
+ pb_session = NULL;
+}
diff --git a/mesh/pb-adv.h b/mesh/pb-adv.h
new file mode 100644
index 000000000..a5870d5a2
--- /dev/null
+++ b/mesh/pb-adv.h
@@ -0,0 +1,23 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2018 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.
+ *
+ */
+
+bool pb_adv_reg(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);
+void pb_adv_unreg(void *user_data);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 09/30] mesh: Acceptor side provisioning implimentation
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (7 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 08/30] mesh: Direction agnostic PB-Adv implimentation Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 10/30] mesh: Initiator " Brian Gix
` (20 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/prov-acceptor.c | 711 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 711 insertions(+)
create mode 100644 mesh/prov-acceptor.c
diff --git a/mesh/prov-acceptor.c b/mesh/prov-acceptor.c
new file mode 100644
index 000000000..8c3e2e358
--- /dev/null
+++ b/mesh/prov-acceptor.c
@@ -0,0 +1,711 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2018 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/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <time.h>
+#include <ell/ell.h>
+
+#include "mesh/mesh-defs.h"
+#include "src/shared/ecc.h"
+
+#include "mesh/util.h"
+#include "mesh/net_keys.h"
+#include "mesh/crypto.h"
+#include "mesh/net.h"
+#include "mesh/error.h"
+#include "mesh/prov.h"
+#include "mesh/provision.h"
+#include "mesh/pb-adv.h"
+#include "mesh/mesh.h"
+#include "mesh/agent.h"
+
+/* Quick size sanity check */
+static const uint16_t expected_pdu_size[] = {
+ 2, /* PROV_INVITE */
+ 12, /* PROV_CAPS */
+ 6, /* PROV_START */
+ 65, /* PROV_PUB_KEY */
+ 1, /* PROV_INP_CMPLT */
+ 17, /* PROV_CONFIRM */
+ 17, /* PROV_RANDOM */
+ 34, /* PROV_DATA */
+ 1, /* PROV_COMPLETE */
+ 2, /* PROV_FAILED */
+};
+
+#define BEACON_TYPE_UNPROVISIONED 0x00
+
+static const uint8_t pkt_filter = MESH_AD_TYPE_PROVISION;
+static const uint8_t bec_filter[] = {MESH_AD_TYPE_BEACON,
+ BEACON_TYPE_UNPROVISIONED};
+
+enum acp_state {
+ ACP_PROV_IDLE = 0,
+ ACP_PROV_CAPS_SENT,
+ ACP_PROV_CAPS_ACKED,
+ ACP_PROV_KEY_SENT,
+ ACP_PROV_KEY_ACKED,
+ ACP_PROV_INP_CMPLT_SENT,
+ ACP_PROV_INP_CMPLT_ACKED,
+ ACP_PROV_CONF_SENT,
+ ACP_PROV_CONF_ACKED,
+ ACP_PROV_RAND_SENT,
+ ACP_PROV_RAND_ACKED,
+ ACP_PROV_CMPLT_SENT,
+ ACP_PROV_FAIL_SENT,
+};
+
+#define MAT_REMOTE_PUBLIC 0x01
+#define MAT_LOCAL_PRIVATE 0x02
+#define MAT_RAND_AUTH 0x04
+#define MAT_SECRET (MAT_REMOTE_PUBLIC | MAT_LOCAL_PRIVATE)
+
+struct mesh_prov_acceptor {
+ mesh_prov_acceptor_complete_func_t cmplt;
+ prov_trans_tx_t trans_tx;
+ void *agent;
+ void *caller_data;
+ void *trans_data;
+ struct l_timeout *timeout;
+ uint32_t to_secs;
+ enum acp_state state;
+ uint8_t transport;
+ uint8_t material;
+ uint8_t expected;
+ int8_t previous;
+ struct conf_input conf_inputs;
+ uint8_t calc_key[16];
+ uint8_t salt[16];
+ uint8_t confirm[16];
+ uint8_t s_key[16];
+ uint8_t s_nonce[13];
+ uint8_t private_key[32];
+ uint8_t secret[32];
+ uint8_t rand_auth_workspace[48];
+};
+
+static struct mesh_prov_acceptor *prov = NULL;
+
+static void acceptor_free()
+{
+
+ if (prov) {
+ l_timeout_remove(prov->timeout);
+ }
+
+ mesh_send_cancel(bec_filter, sizeof(bec_filter));
+ mesh_send_cancel(&pkt_filter, sizeof(pkt_filter));
+
+ if (prov->trans_tx) {
+ if (prov->transport == PB_ADV)
+ pb_adv_unreg(prov->trans_data);
+#if defined(GATT_ENABLED)
+ /* TODO: Cleanup GATT bearer if exists */
+ else if (prov->transport == PB_GATT)
+ pb_gatt_unreg(prov->trans_data);
+#endif
+ }
+
+ l_free(prov);
+ prov = NULL;
+}
+
+static void acp_prov_close(void *user_data, uint8_t reason)
+{
+ /* TODO: Handle Close */
+}
+
+static void prov_to(struct l_timeout *timeout, void *user_data)
+{
+ struct mesh_prov_acceptor *rx_prov = user_data;
+ uint8_t fail_code[2] = {PROV_FAILED, PROV_ERR_UNEXPECTED_ERR};
+
+ if (rx_prov != prov)
+ return;
+
+ prov->timeout = NULL;
+
+ if (prov->cmplt && prov->trans_tx) {
+ prov->cmplt(prov->caller_data, PROV_ERR_TIMEOUT, NULL);
+ prov->cmplt = NULL;
+ prov->trans_tx(prov->trans_data, fail_code, 2);
+ prov->timeout = l_timeout_create(1, prov_to, prov, NULL);
+ return;
+ }
+
+ acceptor_free();
+}
+
+static void acp_prov_open(void *user_data, prov_trans_tx_t trans_tx,
+ void *trans_data, uint8_t transport)
+{
+ struct mesh_prov_acceptor *rx_prov = user_data;
+
+ /* Only one provisioning session may be open at a time */
+ if (rx_prov != prov)
+ return;
+
+ /* Only one provisioning session may be open at a time */
+ if (prov->trans_tx && prov->trans_tx != trans_tx &&
+ prov->transport != transport)
+ return;
+
+ if (transport == PB_ADV) {
+#if defined(GATT_ENABLED)
+ /* TODO: Disable PB-GATT */
+#endif
+ }
+
+#if defined(GATT_ENABLED)
+ else if (transport == PB_GATT) {
+ /* TODO: Disable PB-ADV */
+ pb_adv_unreg(prov);
+ }
+#endif
+
+ else
+ return;
+
+ prov->trans_tx = trans_tx;
+ prov->transport = transport;
+ prov->trans_data = trans_data;
+ prov->timeout = l_timeout_create(prov->to_secs, prov_to, prov, NULL);
+}
+
+static void swap_u256_bytes(uint8_t *u256)
+{
+ int i;
+
+ /* End-to-End byte reflection of 32 octet buffer */
+ for (i = 0; i < 16; i++) {
+ u256[i] ^= u256[31 - i];
+ u256[31 - i] ^= u256[i];
+ u256[i] ^= u256[31 - i];
+ }
+}
+
+static void prov_calc_secret(const uint8_t *pub, const uint8_t *priv,
+ uint8_t *secret)
+{
+ uint8_t tmp[64];
+
+ /* Convert to ECC byte order */
+ memcpy(tmp, pub, 64);
+ swap_u256_bytes(tmp);
+ swap_u256_bytes(tmp + 32);
+
+ ecdh_shared_secret(tmp, priv, secret);
+
+ /* Convert to Mesh byte order */
+ swap_u256_bytes(secret);
+}
+
+static void acp_credentials(struct mesh_prov_acceptor *prov)
+{
+ prov_calc_secret(prov->conf_inputs.prv_pub_key,
+ prov->private_key, prov->secret);
+
+ mesh_crypto_s1(&prov->conf_inputs,
+ sizeof(prov->conf_inputs), prov->salt);
+
+ mesh_crypto_prov_conf_key(prov->secret, prov->salt,
+ prov->calc_key);
+
+ l_getrandom(prov->rand_auth_workspace, 16);
+
+ print_packet("PublicKeyProv", prov->conf_inputs.prv_pub_key, 64);
+ print_packet("PublicKeyDev", prov->conf_inputs.dev_pub_key, 64);
+ print_packet("PrivateKeyLocal", prov->private_key, 32);
+ print_packet("ConfirmationInputs", &prov->conf_inputs,
+ sizeof(prov->conf_inputs));
+ print_packet("ECDHSecret", prov->secret, 32);
+ print_packet("LocalRandom", prov->rand_auth_workspace, 16);
+ print_packet("ConfirmationSalt", prov->salt, 16);
+ print_packet("ConfirmationKey", prov->calc_key, 16);
+}
+
+static uint32_t digit_mod(uint8_t power)
+{
+ uint32_t ret = 1;
+
+ while (power--)
+ ret *= 10;
+
+ return ret;
+}
+
+static void number_cb(void *user_data, mesh_error_t err, uint32_t number)
+{
+ struct mesh_prov_acceptor *rx_prov = user_data;
+ uint8_t out[2];
+
+ if (prov != rx_prov)
+ return;
+
+ if (err) {
+ out[0] = PROV_FAILED;
+ out[1] = PROV_ERR_UNEXPECTED_ERR;
+ prov->trans_tx(prov->trans_data, out, 2);
+ return;
+ }
+
+ /* Save two copies, to generate two confirmation values */
+ l_put_be32(number, prov->rand_auth_workspace + 28);
+ l_put_be32(number, prov->rand_auth_workspace + 44);
+ prov->material |= MAT_RAND_AUTH;
+ out[0] = PROV_INP_CMPLT;
+ prov->trans_tx(prov->trans_data, out, 1);
+}
+
+static void static_cb(void *user_data, mesh_error_t err,
+ uint8_t *key, uint32_t len)
+{
+ struct mesh_prov_acceptor *rx_prov = user_data;
+ uint8_t out[2];
+
+ if (prov != rx_prov)
+ return;
+
+ if (err || !key || len != 16) {
+ out[0] = PROV_FAILED;
+ out[1] = PROV_ERR_UNEXPECTED_ERR;
+ prov->trans_tx(prov->trans_data, out, 2);
+ return;
+ }
+
+ /* Save two copies, to generate two confirmation values */
+ memcpy(prov->rand_auth_workspace + 16, key, 16);
+ memcpy(prov->rand_auth_workspace + 32, key, 16);
+ prov->material |= MAT_RAND_AUTH;
+}
+
+static void priv_key_cb(void *user_data, mesh_error_t err,
+ uint8_t *key, uint32_t len)
+{
+ struct mesh_prov_acceptor *rx_prov = user_data;
+ uint8_t out[2];
+
+ if (prov != rx_prov)
+ return;
+
+ if (err || !key || len != 32) {
+ out[0] = PROV_FAILED;
+ out[1] = PROV_ERR_UNEXPECTED_ERR;
+ prov->trans_tx(prov->trans_data, out, 2);
+ return;
+ }
+
+ memcpy(prov->private_key, key, 32);
+ ecc_make_public_key(prov->private_key,
+ prov->conf_inputs.dev_pub_key);
+
+ /* Convert to Mesh byte order */
+ swap_u256_bytes(prov->conf_inputs.dev_pub_key);
+ swap_u256_bytes(prov->conf_inputs.dev_pub_key + 32);
+
+ prov->material |= MAT_LOCAL_PRIVATE;
+ if ((prov->material & MAT_SECRET) == MAT_SECRET)
+ acp_credentials(prov);
+}
+
+static void acp_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
+{
+ struct mesh_prov_acceptor *rx_prov = user_data;
+ struct mesh_prov_node_info *info;
+ uint8_t *out;
+ uint8_t type = *data++;
+ uint8_t fail_code[2];
+ uint32_t oob_key;
+ uint64_t decode_mic;
+ bool result;
+
+ if (rx_prov != prov || !prov->trans_tx)
+ return;
+
+ l_debug("Provisioning packet received type: %2.2x (%u octets)",
+ type, len);
+
+ if (type == prov->previous) {
+ l_error("Ignore repeated %2.2x packet", type);
+ return;
+ } else if (type > prov->expected || type < prov->previous) {
+ l_error("Expected %2.2x, Got:%2.2x", prov->expected, type);
+ fail_code[1] = PROV_ERR_UNEXPECTED_PDU;
+ goto failure;
+ }
+
+ 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);
+ fail_code[1] = PROV_ERR_INVALID_FORMAT;
+ goto failure;
+ }
+
+ switch (type){
+ case PROV_INVITE: /* Prov Invite */
+ /* Prov Capabilities */
+ out = l_malloc(1 + sizeof(struct mesh_net_prov_caps));
+ out[0] = PROV_CAPS;
+ memcpy(out + 1, &prov->conf_inputs.caps,
+ sizeof(prov->conf_inputs.caps));
+
+ prov->conf_inputs.invite.attention = data[0];
+
+ prov->state = ACP_PROV_CAPS_SENT;
+ prov->expected = PROV_START;
+ prov->trans_tx(prov->trans_data,
+ out, sizeof(prov->conf_inputs.caps) + 1);
+ l_free(out);
+ break;
+
+ case PROV_START: /* Prov Start */
+ memcpy(&prov->conf_inputs.start, data,
+ sizeof(prov->conf_inputs.start));
+
+ if (prov->conf_inputs.start.algorithm ||
+ prov->conf_inputs.start.pub_key > 1 ||
+ prov->conf_inputs.start.auth_method > 3) {
+ fail_code[1] = PROV_ERR_INVALID_FORMAT;
+ goto failure;
+ }
+
+ if (prov->conf_inputs.start.pub_key) {
+ if (prov->conf_inputs.caps.pub_type) {
+ /* Prompt Agent for Private Key of OOB */
+ mesh_agent_request_private_key(prov->agent,
+ priv_key_cb, prov);
+ } else {
+ fail_code[1] = PROV_ERR_INVALID_PDU;
+ goto failure;
+ }
+ } else {
+ /* Ephemeral Public Key requested */
+ ecc_make_key(prov->conf_inputs.dev_pub_key,
+ prov->private_key);
+ swap_u256_bytes(prov->conf_inputs.dev_pub_key);
+ swap_u256_bytes(prov->conf_inputs.dev_pub_key + 32);
+ prov->material |= MAT_LOCAL_PRIVATE;
+ }
+
+ prov->expected = PROV_PUB_KEY;
+ break;
+
+ case PROV_PUB_KEY: /* Public Key */
+ /* Save Key */
+ memcpy(prov->conf_inputs.prv_pub_key, data, 64);
+ prov->material |= MAT_REMOTE_PUBLIC;
+ prov->expected = PROV_CONFIRM;
+
+ if ((prov->material & MAT_SECRET) != MAT_SECRET)
+ return;
+
+ acp_credentials(prov);
+
+ if (!prov->conf_inputs.start.pub_key) {
+ out = l_malloc(65);
+ out[0] = PROV_PUB_KEY;
+ memcpy(out + 1, prov->conf_inputs.dev_pub_key, 64);
+ prov->trans_tx(prov->trans_data, out, 65);
+ l_free(out);
+ }
+
+ /* Start Step 3 */
+ switch (prov->conf_inputs.start.auth_method) {
+ default:
+ case 0:
+ /* Auth Type 3c - No OOB */
+ break;
+
+ case 1:
+ /* Auth Type 3c - Static OOB */
+ /* Prompt Agent for Static OOB */
+ fail_code[1] = mesh_agent_request_static(prov->agent,
+ static_cb, prov);
+
+ if (fail_code[1])
+ goto failure;
+
+ break;
+
+ case 2:
+ /* Auth Type 3a - Output OOB */
+ l_getrandom(&oob_key, sizeof(oob_key));
+ oob_key %= digit_mod(prov->conf_inputs.start.auth_size);
+
+ /* Save two copies, for two confirmation values */
+ l_put_be32(oob_key, prov->rand_auth_workspace + 28);
+ l_put_be32(oob_key, prov->rand_auth_workspace + 44);
+ prov->material |= MAT_RAND_AUTH;
+
+ if (prov->conf_inputs.start.auth_action ==
+ PROV_ACTION_OUT_ALPHA) {
+ /* TODO: Construst NUL-term string to pass */
+ fail_code[1] = mesh_agent_display_string(
+ prov->agent, NULL, NULL, prov);
+ } else {
+ /* Ask Agent to Display U32 */
+ fail_code[1] = mesh_agent_display_number(
+ prov->agent, false,
+ prov->conf_inputs.start.auth_action,
+ oob_key, NULL, prov);
+ }
+
+ if (fail_code[1])
+ goto failure;
+
+ break;
+
+ case 3:
+ /* Auth Type 3b - input OOB */
+ /* Prompt Agent for Input OOB */
+ if (prov->conf_inputs.start.auth_action ==
+ PROV_ACTION_IN_ALPHA) {
+ fail_code[1] = mesh_agent_prompt_alpha(
+ prov->agent,
+ static_cb, prov);
+ } else {
+ fail_code[1] = mesh_agent_prompt_number(
+ prov->agent, false,
+ prov->conf_inputs.start.auth_action,
+ number_cb, prov);
+ }
+
+ if (fail_code[1])
+ goto failure;
+
+ break;
+ }
+
+ prov->expected = PROV_CONFIRM;
+ break;
+
+ case PROV_CONFIRM: /* Confirmation */
+ out = l_malloc(17);
+ out[0] = PROV_CONFIRM;
+
+ /* Calculate and Send our Confirmation */
+ mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
+ 32, out + 1);
+ prov->trans_tx(prov->trans_data, out, 17);
+ l_free(out);
+
+ /* Save Provisioners confirmation for later compare */
+ memcpy(prov->confirm, data, 16);
+ prov->expected = PROV_RANDOM;
+ break;
+
+ case PROV_RANDOM: /* Random Value */
+ out = l_malloc(17);
+ /* Calculate Session key (needed later) while data is fresh */
+ mesh_crypto_prov_prov_salt(prov->salt, data,
+ prov->rand_auth_workspace,
+ prov->salt);
+ mesh_crypto_session_key(prov->secret, prov->salt, prov->s_key);
+ mesh_crypto_nonce(prov->secret, prov->salt, prov->s_nonce);
+
+ /* Calculate expected Provisioner Confirm */
+ memcpy(prov->rand_auth_workspace + 16, data, 16);
+ mesh_crypto_aes_cmac(prov->calc_key,
+ prov->rand_auth_workspace + 16, 32, out);
+
+ /* Compare our calculation with Provisioners */
+ if (memcmp(out, prov->confirm, 16)) {
+ fail_code[1] = PROV_ERR_CONFIRM_FAILED;
+ l_free(out);
+ goto failure;
+ }
+
+ /* Send Random value we used */
+ out[0] = PROV_RANDOM;
+ memcpy(out + 1, prov->rand_auth_workspace, 16);
+ prov->trans_tx(prov->trans_data, out, 17);
+ l_free(out);
+ prov->expected = PROV_DATA;
+ break;
+
+ case PROV_DATA: /* Provisioning Data */
+
+ /* Calculate our device key */
+ mesh_crypto_device_key(prov->secret,
+ prov->salt,
+ prov->calc_key);
+
+ /* Decrypt new node data into workspace */
+ mesh_crypto_aes_ccm_decrypt(prov->s_nonce, prov->s_key,
+ NULL, 0,
+ data, len - 1, prov->rand_auth_workspace,
+ &decode_mic, sizeof(decode_mic));
+
+ /* Validate that the data hasn't been messed with in transit */
+ if (l_get_be64(data + 25) != decode_mic) {
+ l_error("Provisioning Failed-MIC compare");
+ fail_code[1] = PROV_ERR_DECRYPT_FAILED;
+ goto failure;
+ }
+
+ info = l_malloc(sizeof(struct mesh_prov_node_info));
+
+ memcpy(info->device_key, prov->calc_key, 16);
+ memcpy(info->net_key, prov->rand_auth_workspace, 16);
+ info->net_index = l_get_be16(prov->rand_auth_workspace + 16);
+ 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);
+
+ 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->trans_tx(prov->trans_data,
+ prov->rand_auth_workspace, 1);
+ goto cleanup;
+ } else {
+ fail_code[1] = PROV_ERR_UNEXPECTED_ERR;
+ goto failure;
+ }
+ break;
+
+ case PROV_FAILED: /* Provisioning Error -- abort */
+ /* TODO: Call Complete Callback (Fail)*/
+ prov->cmplt(prov->caller_data,
+ data[0] ? data[0] : PROV_ERR_UNEXPECTED_ERR,
+ NULL);
+ prov->cmplt = NULL;
+ goto cleanup;
+ }
+
+ prov->previous = type;
+ return;
+
+failure:
+ fail_code[0] = PROV_FAILED;
+ prov->trans_tx(prov->trans_data, fail_code, 2);
+ if (prov->cmplt)
+ prov->cmplt(prov->caller_data, fail_code[1], NULL);
+ prov->cmplt = NULL;
+
+cleanup:
+ l_timeout_remove(prov->timeout);
+
+ /* Give PB Link 5 seconds to end session */
+ prov->timeout = l_timeout_create(5, prov_to, prov, NULL);
+}
+
+static void acp_prov_ack(void *user_data, uint8_t msg_num)
+{
+ /* TODO: Handle PB-ADV Ack */
+}
+
+
+/* This starts unprovisioned device beacon */
+bool acceptor_start(uint8_t num_ele, uint8_t uuid[16],
+ uint16_t algorithms, uint32_t timeout,
+ struct mesh_agent *agent,
+ mesh_prov_acceptor_complete_func_t complete_cb,
+ void *caller_data)
+{
+ struct mesh_agent_prov_caps *caps;
+ uint8_t beacon[24] = {MESH_AD_TYPE_BEACON,
+ BEACON_TYPE_UNPROVISIONED};
+ uint8_t len = sizeof(beacon) - sizeof(uint32_t);
+ bool result;
+
+ /* Invoked from Join() method in mesh-api.txt, to join a
+ * remote mesh network.
+ */
+
+#if defined(GATT_ENABLED)
+ /* If we support PB-GATT, that means we need to set up a GATT
+ * service, and need the existence of bluetoothd, with it's
+ * own LE capable controller. That is a battle for another day.
+ * We will *always* support PB-ADV.
+ */
+#endif
+ if (prov)
+ return false;
+
+ prov = l_new(struct mesh_prov_acceptor, 1);
+ prov->to_secs = timeout;
+ prov->agent = agent;
+ prov->cmplt = complete_cb;
+ prov->previous = -1;
+ prov->caller_data = caller_data;
+
+ 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);
+ }
+
+ /* Infinitely Beacon until Canceled, or Provisioning Starts */
+ result = mesh_send_pkt(0, 500, beacon, len);
+
+ if (!result)
+ goto error_fail;
+
+ /* Always register for PB-ADV */
+ result = pb_adv_reg(acp_prov_open, acp_prov_close, acp_prov_rx,
+ acp_prov_ack, uuid, prov);
+
+ if (result)
+ return true;
+
+error_fail:
+ acceptor_free();
+ return false;
+}
+
+void acceptor_cancel(void *user_data)
+{
+ acceptor_free();
+}
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 10/30] mesh: Initiator side provisioning implimentation
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (8 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 09/30] mesh: Acceptor side provisioning implimentation Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 11/30] mesh: Rewrite Controler interface for full init Brian Gix
` (19 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/prov-initiator.c | 651 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 651 insertions(+)
create mode 100644 mesh/prov-initiator.c
diff --git a/mesh/prov-initiator.c b/mesh/prov-initiator.c
new file mode 100644
index 000000000..7ac618f4a
--- /dev/null
+++ b/mesh/prov-initiator.c
@@ -0,0 +1,651 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2018 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/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <termios.h>
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <getopt.h>
+#include <time.h>
+#include <ell/ell.h>
+
+#include "mesh/mesh-defs.h"
+#include "src/shared/ecc.h"
+
+#include "mesh/util.h"
+#include "mesh/net_keys.h"
+#include "mesh/crypto.h"
+#include "mesh/net.h"
+#include "mesh/error.h"
+#include "mesh/prov.h"
+#include "mesh/provision.h"
+#include "mesh/pb-adv.h"
+#include "mesh/mesh.h"
+#include "mesh/agent.h"
+
+/* Quick size sanity check */
+static const uint16_t expected_pdu_size[] = {
+ 2, /* PROV_INVITE */
+ 12, /* PROV_CAPS */
+ 6, /* PROV_START */
+ 65, /* PROV_PUB_KEY */
+ 1, /* PROV_INP_CMPLT */
+ 17, /* PROV_CONFIRM */
+ 17, /* PROV_RANDOM */
+ 34, /* PROV_DATA */
+ 1, /* PROV_COMPLETE */
+ 2, /* PROV_FAILED */
+};
+
+#define BEACON_TYPE_UNPROVISIONED 0x00
+
+static const uint8_t pkt_filter = MESH_AD_TYPE_PROVISION;
+
+enum int_state {
+ INT_PROV_IDLE = 0,
+ INT_PROV_INVITE_SENT,
+ INT_PROV_INVITE_ACKED,
+ INT_PROV_START_SENT,
+ INT_PROV_START_ACKED,
+ INT_PROV_KEY_SENT,
+ INT_PROV_KEY_ACKED,
+ INT_PROV_CONF_SENT,
+ INT_PROV_CONF_ACKED,
+ INT_PROV_RAND_SENT,
+ INT_PROV_RAND_ACKED,
+ INT_PROV_DATA_SENT,
+ INT_PROV_DATA_ACKED,
+};
+
+#define MAT_REMOTE_PUBLIC 0x01
+#define MAT_LOCAL_PRIVATE 0x02
+#define MAT_RAND_AUTH 0x04
+#define MAT_SECRET (MAT_REMOTE_PUBLIC | MAT_LOCAL_PRIVATE)
+
+struct mesh_prov_initiator {
+ mesh_prov_initiator_complete_func_t cmplt;
+ prov_trans_tx_t trans_tx;
+ void *agent;
+ void *caller_data;
+ void *trans_data;
+ struct l_timeout *timeout;
+ uint32_t to_secs;
+ enum int_state state;
+ enum trans_type transport;
+ uint8_t material;
+ uint8_t expected;
+ int8_t previous;
+ struct conf_input conf_inputs;
+ uint8_t calc_key[16];
+ uint8_t salt[16];
+ uint8_t confirm[16];
+ uint8_t s_key[16];
+ uint8_t s_nonce[13];
+ uint8_t private_key[32];
+ uint8_t secret[32];
+ uint8_t rand_auth_workspace[48];
+};
+
+static struct mesh_prov_initiator *prov = NULL;
+
+static void initiator_free()
+{
+
+ if (prov) {
+ l_timeout_remove(prov->timeout);
+ }
+
+ mesh_send_cancel(&pkt_filter, sizeof(pkt_filter));
+
+ l_free(prov);
+ prov = NULL;
+}
+
+static void int_prov_close(void *user_data, uint8_t reason)
+{
+ /* TODO: Handle Close */
+}
+
+static void int_prov_open(void *user_data, prov_trans_tx_t trans_tx,
+ void *trans_data, uint8_t transport)
+{
+ struct mesh_prov_initiator *rx_prov = user_data;
+ uint8_t invite[] = { PROV_INVITE, 30 };
+
+ /* Only one provisioning session may be open at a time */
+ if (rx_prov != prov)
+ return;
+
+ /* Only one provisioning session may be open at a time */
+ if (prov->trans_tx && prov->trans_tx != trans_tx &&
+ prov->transport != transport)
+ return;
+
+ /* We only care here if transport does *not* match */
+ if (transport != prov->transport)
+ return;
+
+ /* Always use an ephemeral key when Initiator */
+ ecc_make_key(prov->conf_inputs.prv_pub_key, prov->private_key);
+ prov->material |= MAT_LOCAL_PRIVATE;
+
+ prov->trans_tx = trans_tx;
+ prov->trans_data = trans_data;
+ prov->state = INT_PROV_INVITE_SENT;
+ prov->expected = PROV_CAPS;
+
+ prov->conf_inputs.invite.attention = invite[1];
+ prov->trans_tx(prov->trans_data, invite, sizeof(invite));
+ return;
+}
+
+static void swap_u256_bytes(uint8_t *u256)
+{
+ int i;
+
+ /* End-to-End byte reflection of 32 octet buffer */
+ for (i = 0; i < 16; i++) {
+ u256[i] ^= u256[31 - i];
+ u256[31 - i] ^= u256[i];
+ u256[i] ^= u256[31 - i];
+ }
+}
+
+static void prov_calc_secret(const uint8_t *pub, const uint8_t *priv,
+ uint8_t *secret)
+{
+ uint8_t tmp[64];
+
+ /* Convert to ECC byte order */
+ memcpy(tmp, pub, 64);
+ swap_u256_bytes(tmp);
+ swap_u256_bytes(tmp + 32);
+
+ ecdh_shared_secret(tmp, priv, secret);
+
+ /* Convert to Mesh byte order */
+ swap_u256_bytes(secret);
+}
+
+static void int_credentials(struct mesh_prov_initiator *prov)
+{
+ prov_calc_secret(prov->conf_inputs.dev_pub_key,
+ prov->private_key, prov->secret);
+
+ mesh_crypto_s1(&prov->conf_inputs,
+ sizeof(prov->conf_inputs), prov->salt);
+
+ mesh_crypto_prov_conf_key(prov->secret, prov->salt,
+ prov->calc_key);
+
+ l_getrandom(prov->rand_auth_workspace, 16);
+
+ print_packet("PublicKeyProv", prov->conf_inputs.prv_pub_key, 64);
+ print_packet("PublicKeyDev", prov->conf_inputs.dev_pub_key, 64);
+ print_packet("PrivateKeyLocal", prov->private_key, 32);
+ print_packet("ConfirmationInputs", &prov->conf_inputs,
+ sizeof(prov->conf_inputs));
+ print_packet("ECDHSecret", prov->secret, 32);
+ print_packet("LocalRandom", prov->rand_auth_workspace, 16);
+ print_packet("ConfirmationSalt", prov->salt, 16);
+ print_packet("ConfirmationKey", prov->calc_key, 16);
+}
+
+static uint8_t u16_high_bit(uint16_t mask)
+{
+ uint8_t cnt = 0;
+
+ if (!mask)
+ return 0xff;
+
+ while (mask & 0xfffe) {
+ cnt++;
+ mask >>= 1;
+ }
+
+ return cnt;
+}
+
+static uint32_t digit_mod(uint8_t power)
+{
+ uint32_t ret = 1;
+
+ while (power--)
+ ret *= 10;
+
+ return ret;
+}
+
+static void calc_local_material(const uint8_t *random)
+{
+ /* Calculate SessionKey while the data is fresh */
+ mesh_crypto_prov_prov_salt(prov->salt,
+ prov->rand_auth_workspace, random,
+ prov->salt);
+ mesh_crypto_session_key(prov->secret, prov->salt,
+ prov->s_key);
+ mesh_crypto_nonce(prov->secret, prov->salt, prov->s_nonce);
+
+ print_packet("SessionKey", prov->s_key, sizeof(prov->s_key));
+ print_packet("Nonce", prov->s_nonce, sizeof(prov->s_nonce));
+ print_packet("RandomDevice", prov->rand_auth_workspace, 16);
+}
+
+static void number_cb(void *user_data, mesh_error_t err, uint32_t number)
+{
+ struct mesh_prov_initiator *rx_prov = user_data;
+ uint8_t out[2];
+
+ if (prov != rx_prov)
+ return;
+
+ if (err) {
+ out[0] = PROV_FAILED;
+ out[1] = PROV_ERR_UNEXPECTED_ERR;
+ prov->trans_tx(prov->trans_data, out, 2);
+ return;
+ }
+
+ /* Save two copies, to generate two confirmation values */
+ l_put_be32(number, prov->rand_auth_workspace + 28);
+ l_put_be32(number, prov->rand_auth_workspace + 44);
+ prov->material |= MAT_RAND_AUTH;
+}
+
+static void static_cb(void *user_data, mesh_error_t err,
+ uint8_t *key, uint32_t len)
+{
+ struct mesh_prov_initiator *rx_prov = user_data;
+ uint8_t out[2];
+
+ if (prov != rx_prov)
+ return;
+
+ if (err || !key || len != 16) {
+ out[0] = PROV_FAILED;
+ out[1] = PROV_ERR_UNEXPECTED_ERR;
+ prov->trans_tx(prov->trans_data, out, 2);
+ return;
+ }
+
+ memcpy(prov->rand_auth_workspace + 16, key, 16);
+ memcpy(prov->rand_auth_workspace + 32, key, 16);
+ prov->material |= MAT_RAND_AUTH;
+}
+
+static void pub_key_cb(void *user_data, mesh_error_t err,
+ uint8_t *key, uint32_t len)
+{
+ struct mesh_prov_initiator *rx_prov = user_data;
+ uint8_t out[2];
+
+ if (prov != rx_prov)
+ return;
+
+ if (err || !key || len != 64) {
+ out[0] = PROV_FAILED;
+ out[1] = PROV_ERR_UNEXPECTED_ERR;
+ prov->trans_tx(prov->trans_data, out, 2);
+ return;
+ }
+
+ memcpy(prov->conf_inputs.dev_pub_key, key, 64);
+ prov->material |= MAT_REMOTE_PUBLIC;
+
+ if ((prov->material & MAT_SECRET) == MAT_SECRET)
+ int_credentials(prov);
+}
+
+static void int_prov_rx(void *user_data, const uint8_t *data, uint16_t len)
+{
+ struct mesh_prov_initiator *rx_prov = user_data;
+ uint8_t *out;
+ uint8_t type = *data++;
+ uint8_t fail_code[2];
+ uint32_t oob_key;
+ uint64_t mic;
+
+ if (rx_prov != prov || !prov->trans_tx)
+ return;
+
+ l_debug("Provisioning packet received type: %2.2x (%u octets)",
+ type, len);
+
+ if (type == prov->previous) {
+ l_error("Ignore repeated %2.2x packet", type);
+ return;
+ } else if (type > prov->expected || type < prov->previous) {
+ l_error("Expected %2.2x, Got:%2.2x", prov->expected, type);
+ fail_code[1] = PROV_ERR_UNEXPECTED_PDU;
+ goto failure;
+ }
+
+ 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);
+ fail_code[1] = PROV_ERR_INVALID_FORMAT;
+ goto failure;
+ }
+
+ switch (type) {
+ case PROV_CAPS: /* Capabilities */
+ prov->state = INT_PROV_INVITE_ACKED;
+ memcpy(&prov->conf_inputs.caps, data,
+ sizeof(prov->conf_inputs.caps));
+
+ l_debug("Got Num Ele %d", data[0]);
+ l_debug("Got alg %4.4x", l_get_be16(data + 1));
+ l_debug("Got pub_type %d", data[3]);
+ l_debug("Got static_type %d", data[4]);
+ l_debug("Got output_size %d", data[5]);
+ l_debug("Got output_action %d", l_get_be16(data + 6));
+ l_debug("Got input_size %d", data[8]);
+ l_debug("Got input_action %d", l_get_be16(data + 9));
+
+ if (!(l_get_be16(data + 1) & 0x0001)) {
+ l_error("Unsupported Algorithm");
+ fail_code[1] = PROV_ERR_INVALID_FORMAT;
+ goto failure;
+ }
+
+ /* If Public Key available Out of Band, use it */
+ if (prov->conf_inputs.caps.pub_type) {
+ prov->conf_inputs.start.pub_key = 0x01;
+ prov->expected = PROV_CONFIRM;
+ /* Prompt Agent for remote Public Key */
+ mesh_agent_request_public_key(prov->agent,
+ pub_key_cb, prov);
+
+ /* Nothing else for us to do now */
+ } else
+ prov->expected = PROV_PUB_KEY;
+
+ /* Parse OOB Options, prefer static, then out, then in */
+ if (prov->conf_inputs.caps.static_type) {
+
+ prov->conf_inputs.start.auth_method = 0x01;
+
+ } else if (prov->conf_inputs.caps.output_size &&
+ prov->conf_inputs.caps.output_action) {
+
+ prov->conf_inputs.start.auth_method = 0x02;
+ prov->conf_inputs.start.auth_action =
+ u16_high_bit(l_get_be16(data + 6));
+ prov->conf_inputs.start.auth_size =
+ (data[5] > 8 ? 8 : data[5]);
+
+ } else if (prov->conf_inputs.caps.input_size &&
+ prov->conf_inputs.caps.input_action) {
+
+ prov->conf_inputs.start.auth_method = 0x03;
+ prov->conf_inputs.start.auth_action =
+ u16_high_bit(l_get_be16(data + 9));
+ prov->conf_inputs.start.auth_size =
+ (data[8] > 8 ? 8 : data[8]);
+
+ }
+
+ out = l_malloc(1 + sizeof(prov->conf_inputs.start));
+ out[0] = PROV_START;
+ memcpy(out + 1, &prov->conf_inputs.start,
+ sizeof(prov->conf_inputs.start));
+
+ prov->state = INT_PROV_START_SENT;
+ prov->trans_tx(prov->trans_data, out,
+ sizeof(prov->conf_inputs.start) + 1);
+ l_free(out);
+ break;
+
+ case PROV_PUB_KEY: /* Public Key */
+ /* If we expected Pub Key Out-Of-Band, then fail */
+ if (prov->conf_inputs.start.pub_key) {
+ fail_code[1] = PROV_ERR_INVALID_PDU;
+ goto failure;
+ }
+
+ memcpy(prov->conf_inputs.dev_pub_key, data, 64);
+ prov->material |= MAT_REMOTE_PUBLIC;
+ prov->expected = PROV_CONFIRM;
+
+ if ((prov->material & MAT_SECRET) != MAT_SECRET)
+ return;
+
+ int_credentials(prov);
+ prov->state = INT_PROV_KEY_ACKED;
+
+ prov->expected = PROV_CONFIRM;
+
+ memset(prov->rand_auth_workspace + 16, 0, 32);
+ switch (prov->conf_inputs.start.auth_method) {
+ default:
+ case 0:
+ /* Auth Type 3c - No OOB */
+ prov->material |= MAT_RAND_AUTH;
+ break;
+ case 1:
+ /* Auth Type 3c - Static OOB */
+ /* Prompt Agent for Static OOB */
+ fail_code[1] = mesh_agent_request_static(prov->agent,
+ static_cb, prov);
+
+ if (fail_code[1])
+ goto failure;
+
+ break;
+ case 2:
+ /* Auth Type 3a - Output OOB */
+ /* Prompt Agent for Output OOB */
+ if (prov->conf_inputs.start.auth_action ==
+ PROV_ACTION_OUT_ALPHA) {
+ fail_code[1] = mesh_agent_prompt_alpha(
+ prov->agent,
+ static_cb, prov);
+ } else {
+ fail_code[1] = mesh_agent_prompt_number(
+ prov->agent, true,
+ prov->conf_inputs.start.auth_action,
+ number_cb, prov);
+ }
+
+ if (fail_code[1])
+ goto failure;
+
+ break;
+
+
+ case 3:
+ /* Auth Type 3b - input OOB */
+ l_getrandom(&oob_key, sizeof(oob_key));
+ oob_key %= digit_mod(prov->conf_inputs.start.auth_size);
+
+ /* Save two copies, for two confirmation values */
+ l_put_be32(oob_key, prov->rand_auth_workspace + 28);
+ l_put_be32(oob_key, prov->rand_auth_workspace + 44);
+ prov->material |= MAT_RAND_AUTH;
+ /* Ask Agent to Display U32 */
+ if (prov->conf_inputs.start.auth_action ==
+ PROV_ACTION_IN_ALPHA) {
+ /* TODO: Construst NUL-term string to pass */
+ fail_code[1] = mesh_agent_display_string(
+ prov->agent, NULL, NULL, prov);
+ } else {
+ fail_code[1] = mesh_agent_display_number(
+ prov->agent, false,
+ prov->conf_inputs.start.auth_action,
+ oob_key, NULL, prov);
+ }
+
+ if (fail_code[1])
+ goto failure;
+
+ break;
+
+
+ }
+ break;
+
+ case PROV_INP_CMPLT: /* Provisioning Input Complete */
+ /* TODO: Cancel Agent prompt */
+ prov->expected = PROV_CONFIRM;
+ out = l_malloc(17);
+ out[0] = PROV_CONFIRM;
+ mesh_crypto_aes_cmac(prov->calc_key, prov->rand_auth_workspace,
+ 32, out + 1);
+ prov->trans_tx(prov->trans_data, out, 17);
+ l_free(out);
+ break;
+
+ case PROV_CONFIRM: /* Confirmation */
+ prov->state = INT_PROV_CONF_ACKED;
+ /* RXed Device Confirmation */
+ memcpy(prov->confirm, data, 16);
+ print_packet("ConfirmationDevice", prov->confirm, 16);
+ prov->expected = PROV_RANDOM;
+ out = l_malloc(17);
+ out[0] = PROV_RANDOM;
+ memcpy(out + 1, prov->rand_auth_workspace, 16);
+ prov->trans_tx(prov->trans_data, out, 17);
+ l_free(out);
+ break;
+
+ case PROV_RANDOM: /* Random */
+ prov->state = INT_PROV_RAND_ACKED;
+
+ /* RXed Device Confirmation */
+ memcpy(prov->rand_auth_workspace + 16, data, 16);
+ print_packet("RandomDevice", data, 16);
+ calc_local_material(data);
+
+ mesh_crypto_aes_cmac(prov->calc_key,
+ prov->rand_auth_workspace + 16,
+ 32, prov->rand_auth_workspace);
+
+ if (memcmp(prov->rand_auth_workspace, prov->confirm, 16)) {
+ l_error("Provisioning Failed-Confirm compare)");
+ fail_code[1] = PROV_ERR_CONFIRM_FAILED;
+ goto failure;
+ }
+
+ if (prov->state == INT_PROV_RAND_ACKED) {
+ prov->expected = PROV_COMPLETE;
+ out = l_malloc(34);
+ out[0] = PROV_DATA;
+ /* TODO: Fill Prov Data Structure */
+ /* Encrypt Prov Data */
+ mesh_crypto_aes_ccm_encrypt(prov->s_nonce, prov->s_key,
+ NULL, 0,
+ out + 1,
+ 25,
+ out + 1,
+ &mic, sizeof(mic));
+ prov->trans_tx(prov->trans_data, out, 34);
+ l_free(out);
+ }
+ break;
+
+ case PROV_COMPLETE: /* Complete */
+ l_info("Provisioning Complete");
+ prov->state = INT_PROV_IDLE;
+ //mesh_prov_close(prov, 0);
+ break;
+
+ case PROV_FAILED: /* Failed */
+ l_error("Provisioning Failed (reason: %d)", data[0]);
+ //mesh_prov_close(prov, data[0]);
+ break;
+
+ default:
+ l_error("Unknown Pkt %2.2x", type);
+ fail_code[1] = PROV_ERR_UNEXPECTED_PDU;
+ goto failure;
+ }
+
+ prov->previous = type;
+ return;
+
+failure:
+ fail_code[0] = PROV_FAILED;
+ prov->trans_tx(prov->trans_data, fail_code, 2);
+ /* TODO: Call Complete Callback (Fail)*/
+}
+
+static void int_prov_ack(void *user_data, uint8_t msg_num)
+{
+ /* TODO: Handle PB-ADV Ack */
+}
+
+
+bool initiator_start(enum trans_type transport,
+ uint8_t uuid[16],
+ uint16_t max_ele,
+ uint16_t server, /* Only valid for PB-Remote */
+ uint32_t timeout, /* in seconds from mesh.conf */
+ struct mesh_agent *agent,
+ mesh_prov_initiator_complete_func_t complete_cb,
+ void *caller_data)
+{
+ bool result;
+
+ /* Invoked from Add() method in mesh-api.txt, to add a
+ * remote unprovisioned device network.
+ */
+
+#if defined(GATT_ENABLED)
+ /* If we support PB-GATT, that means we need to set up a GATT
+ * service, and need the existence of bluetoothd, with it's
+ * own LE capable controller. That is a battle for another day.
+ * We will *always* support PB-ADV.
+ */
+#endif
+ if (prov)
+ return false;
+
+ prov = l_new(struct mesh_prov_initiator, 1);
+ prov->to_secs = timeout;
+ prov->agent = agent;
+ prov->cmplt = complete_cb;
+ prov->caller_data = caller_data;
+ prov->previous = -1;
+
+ /* Always register for PB-ADV */
+ result = pb_adv_reg(int_prov_open, int_prov_close, int_prov_rx,
+ int_prov_ack, uuid, prov);
+
+ if (result)
+ return true;
+
+ initiator_free();
+ return false;
+}
+
+void initiator_cancel(void *user_data)
+{
+ initiator_free();
+}
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 11/30] mesh: Rewrite Controler interface for full init
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (9 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 10/30] mesh: Initiator " Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 12/30] mesh: Unchanged variables set to const Brian Gix
` (18 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/mesh-io-generic.c | 148 +++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 137 insertions(+), 11 deletions(-)
diff --git a/mesh/mesh-io-generic.c b/mesh/mesh-io-generic.c
index 52514e280..59e694f00 100644
--- a/mesh/mesh-io-generic.c
+++ b/mesh/mesh-io-generic.c
@@ -30,7 +30,6 @@
#include "monitor/bt.h"
#include "src/shared/hci.h"
-#include "mesh/display.h"
#include "mesh/mesh-io.h"
#include "mesh/mesh-io-api.h"
@@ -177,6 +176,115 @@ static void event_callback(const void *buf, uint8_t size, void *user_data)
}
}
+static void local_commands_callback(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_rsp_read_local_commands *rsp = data;
+
+ if (rsp->status)
+ l_error("Failed to read local commands");
+}
+
+static void local_features_callback(const void *data, uint8_t size,
+ void *user_data)
+{
+ const struct bt_hci_rsp_read_local_features *rsp = data;
+
+ if (rsp->status)
+ l_error("Failed to read local features");
+}
+
+static void hci_generic_callback(const void *data, uint8_t size,
+ void *user_data)
+{
+ uint8_t status = l_get_u8(data);
+
+ if (status)
+ l_error("Failed to initialize HCI");
+}
+
+static void configure_hci(struct mesh_io_private *io)
+{
+ struct bt_hci_cmd_le_set_scan_parameters cmd;
+ struct bt_hci_cmd_set_event_mask cmd_sem;
+ struct bt_hci_cmd_le_set_event_mask cmd_slem;
+
+ /* Set scan parameters */
+ cmd.type = 0x00; /* Passive Scanning. No scanning PDUs shall be sent */
+ cmd.interval = 0x0030; /* Scan Interval = N * 0.625ms */
+ cmd.window = 0x0030; /* Scan Window = N * 0.625ms */
+ cmd.own_addr_type = 0x00; /* Public Device Address */
+ /* Accept all advertising packets except directed advertising packets
+ * not addressed to this device (default). */
+ cmd.filter_policy = 0x00;
+
+ /* Set event mask
+ *
+ * Mask: 0x2000800002008890
+ * Disconnection Complete
+ * Encryption Change
+ * Read Remote Version Information Complete
+ * Hardware Error
+ * Data Buffer Overflow
+ * Encryption Key Refresh Complete
+ * LE Meta
+ */
+ cmd_sem.mask[0] = 0x90;
+ cmd_sem.mask[1] = 0x88;
+ cmd_sem.mask[2] = 0x00;
+ cmd_sem.mask[3] = 0x02;
+ cmd_sem.mask[4] = 0x00;
+ cmd_sem.mask[5] = 0x80;
+ cmd_sem.mask[6] = 0x00;
+ cmd_sem.mask[7] = 0x20;
+
+ /* Set LE event mask
+ *
+ * Mask: 0x000000000000087f
+ * LE Connection Complete
+ * LE Advertising Report
+ * LE Connection Update Complete
+ * LE Read Remote Used Features Complete
+ * LE Long Term Key Request
+ * LE Remote Connection Parameter Request
+ * LE Data Length Change
+ * LE PHY Update Complete
+ */
+ cmd_slem.mask[0] = 0x7f;
+ cmd_slem.mask[1] = 0x08;
+ cmd_slem.mask[2] = 0x00;
+ cmd_slem.mask[3] = 0x00;
+ cmd_slem.mask[4] = 0x00;
+ cmd_slem.mask[5] = 0x00;
+ cmd_slem.mask[6] = 0x00;
+ cmd_slem.mask[7] = 0x00;
+
+ /* TODO: Move to suitable place. Set suitable masks */
+ /* Reset Command */
+ bt_hci_send(io->hci, BT_HCI_CMD_RESET, NULL, 0, hci_generic_callback,
+ NULL, NULL);
+
+ /* Read local supported commands */
+ bt_hci_send(io->hci, BT_HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0,
+ local_commands_callback, NULL, NULL);
+
+ /* Read local supported features */
+ bt_hci_send(io->hci, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0,
+ local_features_callback, NULL, NULL);
+
+ /* Set event mask */
+ bt_hci_send(io->hci, BT_HCI_CMD_SET_EVENT_MASK, &cmd_sem,
+ sizeof(cmd_sem), hci_generic_callback, NULL, NULL);
+
+ /* Set LE event mask */
+ bt_hci_send(io->hci, BT_HCI_CMD_LE_SET_EVENT_MASK, &cmd_slem,
+ sizeof(cmd_slem), hci_generic_callback, NULL, NULL);
+
+ /* Scan Params */
+ bt_hci_send(io->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS, &cmd,
+ sizeof(cmd), hci_generic_callback, NULL, NULL);
+}
+
static bool dev_init(uint16_t index, struct mesh_io *io)
{
struct mesh_io_private *tmp;
@@ -198,6 +306,8 @@ static bool dev_init(uint16_t index, struct mesh_io *io)
if (!tmp->hci)
goto fail;
+ configure_hci(tmp);
+
bt_hci_register(tmp->hci, BT_HCI_EVT_LE_META_EVENT,
event_callback, io, NULL);
@@ -480,7 +590,6 @@ static bool send_tx(struct mesh_io *io, struct mesh_io_send_info *info,
if (!info || !data || !len || len > sizeof(tx->pkt))
return false;
-
tx = l_new(struct tx_pkt, 1);
if (!tx)
return false;
@@ -524,7 +633,7 @@ static bool find_by_pattern(const void *a, const void *b)
return (!memcmp(tx->pkt, pattern->data, pattern->len));
}
-static bool tx_cancel(struct mesh_io *io, uint8_t *data, uint8_t len)
+static bool tx_cancel(struct mesh_io *io, const uint8_t *data, uint8_t len)
{
struct mesh_io_private *pvt = io->pvt;
struct tx_pkt *tx;
@@ -568,13 +677,25 @@ static bool find_by_filter_id(const void *a, const void *b)
return rx_reg->filter_id == filter_id;
}
+static void set_recv_scan_enable(const void *buf, uint8_t size,
+ void *user_data)
+{
+ struct mesh_io_private *pvt = user_data;
+ struct bt_hci_cmd_le_set_scan_enable cmd;
+
+ cmd.enable = 0x01; /* Enable scanning */
+ cmd.filter_dup = 0x00; /* Report duplicates */
+ bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
+ &cmd, sizeof(cmd), NULL, NULL, NULL);
+}
+
static bool recv_register(struct mesh_io *io, uint8_t filter_id,
mesh_io_recv_func_t cb, void *user_data)
{
- struct bt_hci_cmd_le_set_scan_enable cmd;
+ struct bt_hci_cmd_le_set_scan_parameters cmd;
struct mesh_io_private *pvt = io->pvt;
struct pvt_rx_reg *rx_reg;
- bool scanning;
+ bool already_scanning;
l_info("%s %d", __func__, filter_id);
if (!cb || !filter_id || filter_id > sizeof(pvt->filters))
@@ -593,15 +714,20 @@ static bool recv_register(struct mesh_io *io, uint8_t filter_id,
rx_reg->cb = cb;
rx_reg->user_data = user_data;
- scanning = !l_queue_isempty(pvt->rx_regs);
+ already_scanning = !l_queue_isempty(pvt->rx_regs);
l_queue_push_head(pvt->rx_regs, rx_reg);
- if (!scanning) {
- cmd.enable = 0x01; /* Enable scanning */
- cmd.filter_dup = 0x00; /* Report duplicates */
- bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_ENABLE,
- &cmd, sizeof(cmd), NULL, NULL, NULL);
+ if (!already_scanning) {
+ cmd.type = 0x00; /* Passive scanning */
+ cmd.interval = L_CPU_TO_LE16(0x0010); /* 10 ms */
+ cmd.window = L_CPU_TO_LE16(0x0010); /* 10 ms */
+ cmd.own_addr_type = 0x01; /* ADDR_TYPE_RANDOM */
+ cmd.filter_policy = 0x00; /* Accept all */
+
+ bt_hci_send(pvt->hci, BT_HCI_CMD_LE_SET_SCAN_PARAMETERS,
+ &cmd, sizeof(cmd),
+ set_recv_scan_enable, pvt, NULL);
}
return true;
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 12/30] mesh: Unchanged variables set to const
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (10 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 11/30] mesh: Rewrite Controler interface for full init Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 13/30] mesh: centralize generic utilities Brian Gix
` (17 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/mesh-io-api.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mesh/mesh-io-api.h b/mesh/mesh-io-api.h
index f69fceeb2..acf12445d 100644
--- a/mesh/mesh-io-api.h
+++ b/mesh/mesh-io-api.h
@@ -31,7 +31,7 @@ typedef bool (*mesh_io_deregister_t)(struct mesh_io *io, uint8_t filter_id);
typedef bool (*mesh_io_filter_set_t)(struct mesh_io *io,
uint8_t filter_id, const uint8_t *data, uint8_t len,
mesh_io_status_func_t callback, void *user_data);
-typedef bool (*mesh_io_tx_cancel_t)(struct mesh_io *io, uint8_t *pattern,
+typedef bool (*mesh_io_tx_cancel_t)(struct mesh_io *io, const uint8_t *pattern,
uint8_t len);
struct mesh_io_api {
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 13/30] mesh: centralize generic utilities
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (11 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 12/30] mesh: Unchanged variables set to const Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 14/30] mesh: re-arrange provisioning for DBus API Brian Gix
` (16 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/util.c | 26 ++++++++++++++++++++++++++
mesh/util.h | 1 +
2 files changed, 27 insertions(+)
diff --git a/mesh/util.c b/mesh/util.c
index 2cdcdf37d..ac0294742 100644
--- a/mesh/util.c
+++ b/mesh/util.c
@@ -26,10 +26,36 @@
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
+#include <unistd.h>
+#include <termios.h>
#include <time.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+
+#include <ell/ell.h>
#include "mesh/util.h"
+void print_packet(const char *label, const void *data, uint16_t size)
+{
+ struct timeval pkt_time;
+
+ gettimeofday(&pkt_time, NULL);
+
+ if (size > 0) {
+ char *str;
+
+ str = l_util_hexstring(data, size);
+ l_debug("%05d.%03d %s: %s",
+ (uint32_t) pkt_time.tv_sec % 100000,
+ (uint32_t) pkt_time.tv_usec/1000, label, str);
+ l_free(str);
+ } else
+ l_debug("%05d.%03d %s: empty",
+ (uint32_t) pkt_time.tv_sec % 100000,
+ (uint32_t) pkt_time.tv_usec/1000, label);
+}
+
uint32_t get_timestamp_secs(void)
{
struct timespec ts;
diff --git a/mesh/util.h b/mesh/util.h
index 61110104a..b8efb6521 100644
--- a/mesh/util.h
+++ b/mesh/util.h
@@ -22,3 +22,4 @@ uint32_t get_timestamp_secs(void);
bool str2hex(const char *str, uint16_t in_len, uint8_t *out,
uint16_t out_len);
size_t hex2str(uint8_t *in, size_t in_len, char *out, size_t out_len);
+void print_packet(const char *label, const void *data, uint16_t size);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 14/30] mesh: re-arrange provisioning for DBus API
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (12 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 13/30] mesh: centralize generic utilities Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 15/30] mesh: Re-architect " Brian Gix
` (15 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/prov.h | 14 +++++--
mesh/provision.h | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
2 files changed, 112 insertions(+), 14 deletions(-)
diff --git a/mesh/prov.h b/mesh/prov.h
index 09fe6c3cd..61ec08e10 100644
--- a/mesh/prov.h
+++ b/mesh/prov.h
@@ -47,11 +47,17 @@ enum mesh_prov_mode {
};
struct mesh_prov;
-typedef void (*mesh_prov_open_func_t)(struct mesh_prov *prov);
-typedef void (*mesh_prov_close_func_t)(struct mesh_prov *prov, uint8_t reason);
+
+typedef void (*prov_trans_tx_t)(void *trans_data, uint8_t *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_receive_func_t)(const void *data, uint16_t size,
- 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,
+ uint16_t size);
+
struct prov_invite {
uint8_t attention;
diff --git a/mesh/provision.h b/mesh/provision.h
index 0c59bf037..be91c5272 100644
--- a/mesh/provision.h
+++ b/mesh/provision.h
@@ -17,14 +17,106 @@
*
*/
+
+/*
+size: hard define (mesh.confOOB_NUMBEROOB_NUMBER)
+ oob size - 8 if alpha or numeric
+ else 1 if mask is non zero
+ else 0
+*/
+struct bt_mesh;
struct mesh_prov;
-struct l_queue;
-
-void initiator_prov_open(struct mesh_prov *prov);
-void initiator_prov_close(struct mesh_prov *prov, uint8_t reason);
-void initiator_prov_receive(const void *pkt, uint16_t size,
- struct mesh_prov *prov);
-void acceptor_prov_open(struct mesh_prov *prov);
-void acceptor_prov_close(struct mesh_prov *prov, uint8_t reason);
-void acceptor_prov_receive(const void *pkt, uint16_t size,
- struct mesh_prov *prov);
+struct mesh_agent;
+
+/* Provisioner Agent Response Types */
+#define OOB_CANCEL 0x00
+#define OOB_PRIV_KEY 0x01
+#define OOB_PUB_KEY 0x02
+#define OOB_NUMBER 0x03
+#define OOB_STATIC 0x04
+#define OOB_NUMBER_DISPLAY 0x05
+
+/* Spec defined Provisioning message types */
+#define PROV_INVITE 0x00
+#define PROV_CAPS 0x01
+#define PROV_START 0x02
+#define PROV_PUB_KEY 0x03
+#define PROV_INP_CMPLT 0x04
+#define PROV_CONFIRM 0x05
+#define PROV_RANDOM 0x06
+#define PROV_DATA 0x07
+#define PROV_COMPLETE 0x08
+#define PROV_FAILED 0x09
+
+/* Spec defined Error Codes */
+#define PROV_ERR_SUCCESS 0x00
+#define PROV_ERR_INVALID_PDU 0x01
+#define PROV_ERR_INVALID_FORMAT 0x02
+#define PROV_ERR_UNEXPECTED_PDU 0x03
+#define PROV_ERR_CONFIRM_FAILED 0x04
+#define PROV_ERR_INSUF_RESOURCE 0x05
+#define PROV_ERR_DECRYPT_FAILED 0x06
+#define PROV_ERR_UNEXPECTED_ERR 0x07
+#define PROV_ERR_CANT_ASSIGN_ADDR 0x08
+/* Internally generated Error Codes */
+#define PROV_ERR_TIMEOUT 0xFF
+
+/* Provisioner Action values */
+/* IN */
+#define PROV_ACTION_PUSH 0x00
+#define PROV_ACTION_TWIST 0x01
+#define PROV_ACTION_IN_NUMERIC 0x02
+#define PROV_ACTION_IN_ALPHA 0x03
+/* OUT */
+#define PROV_ACTION_BLINK 0x00
+#define PROV_ACTION_BEEP 0x01
+#define PROV_ACTION_VIBRATE 0x02
+#define PROV_ACTION_OUT_NUMERIC 0x03
+#define PROV_ACTION_OUT_ALPHA 0x04
+
+/* OOB_Info defines from Table 3.54 of Mesh profile Specification v1.0 */
+#define OOB_INFO_URI_HASH 0x0002
+
+/* PB_REMOTE not supported from unprovisioned state */
+enum trans_type {
+ PB_ADV = 0,
+ PB_GATT,
+};
+
+#define PROV_FLAG_KR 0x01
+#define PROV_FLAG_IVU 0x02
+
+struct mesh_prov_node_info {
+ uint32_t iv_index;
+ uint16_t unicast;
+ uint16_t net_index;
+ uint8_t net_key[16];
+ uint8_t device_key[16];
+ uint8_t flags; /* IVU and KR bits */
+};
+
+typedef bool (*mesh_prov_acceptor_complete_func_t)(void *user_data,
+ uint8_t status,
+ struct mesh_prov_node_info *info);
+
+typedef bool (*mesh_prov_initiator_complete_func_t)(void *user_data,
+ uint8_t status,
+ struct mesh_prov_node_info *info);
+
+/* This starts unprovisioned device beacon */
+bool acceptor_start(uint8_t num_ele, uint8_t uuid[16],
+ 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,
+ uint8_t uuid[16],
+ uint16_t max_ele,
+ uint16_t server, /* Only valid for PB-Remote */
+ uint32_t timeout, /* in seconds from mesh.conf */
+ struct mesh_agent *agent,
+ mesh_prov_initiator_complete_func_t complete_cb,
+ void *caller_data);
+void initiator_cancel(void *user_data);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 15/30] mesh: Re-architect for DBus API
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (13 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 14/30] mesh: re-arrange provisioning for DBus API Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 16/30] mesh: Make config model handle multiple nodes Brian Gix
` (14 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/mesh.c | 625 ++++++++++++++++++++++++++++++++++++++++++++++--------------
mesh/mesh.h | 27 ++-
2 files changed, 505 insertions(+), 147 deletions(-)
diff --git a/mesh/mesh.c b/mesh/mesh.c
index d1d409672..e862a5861 100644
--- a/mesh/mesh.c
+++ b/mesh/mesh.c
@@ -36,9 +36,24 @@
#include "mesh/node.h"
#include "mesh/net.h"
#include "mesh/storage.h"
-#include "mesh/cfgmod.h"
+#include "mesh/prov.h"
+#include "mesh/provision.h"
#include "mesh/model.h"
+#include "mesh/dbus.h"
+#include "mesh/error.h"
#include "mesh/mesh.h"
+#include "mesh/agent.h"
+
+#define MESH_COMP_MAX_LEN 378
+
+/*
+ * The default values for mesh configuration. Can be
+ * overwritten by values from mesh.conf
+ */
+#define DEFAULT_PROV_TIMEOUT 60
+#define DEFAULT_ALGORITHMS 0x0001
+
+/* TODO: add more default values */
struct scan_filter {
uint8_t id;
@@ -46,42 +61,49 @@ struct scan_filter {
};
struct bt_mesh {
- struct mesh_net *net;
struct mesh_io *io;
struct l_queue *filters;
- int ref_count;
- uint16_t index;
+ prov_rx_cb_t prov_rx;
+ void *prov_data;
+ uint32_t prov_timeout;
+ uint16_t algorithms;
uint16_t req_index;
uint8_t max_filters;
};
+struct join_data{
+ struct l_dbus_message *msg;
+ struct mesh_agent *agent;
+ const char *sender;
+ const char *app_path;
+ struct mesh_node *node;
+ uint32_t disc_watch;
+ uint8_t uuid[16];
+};
+
+struct attach_data {
+ uint64_t token;
+ struct l_dbus_message *msg;
+ const char *app;
+};
+
+static struct bt_mesh mesh;
static struct l_queue *controllers;
-static struct l_queue *mesh_list;
static struct mgmt *mgmt_mesh;
static bool initialized;
-static struct bt_mesh *current;
+
+/* We allow only one outstanding Join request */
+static struct join_data *join_pending;
+
+/* Pending Attach requests */
+static struct l_queue *attach_queue;
static bool simple_match(const void *a, const void *b)
{
return a == b;
}
-static void save_exit_config(struct bt_mesh *mesh)
-{
- const char *cfg_filename;
-
- if (!mesh_net_cfg_file_get(mesh->net, &cfg_filename) || !cfg_filename)
- return;
-
- /* Preserve the last sequence number before saving configuration */
- storage_local_write_sequence_number(mesh->net,
- mesh_net_get_seq_num(mesh->net));
-
- if (storage_save_config(mesh->net, cfg_filename, true, NULL, NULL))
- l_info("Saved final configuration to %s", cfg_filename);
-}
-
-static void start_io(struct bt_mesh *mesh, uint16_t index)
+static void start_io(uint16_t index)
{
struct mesh_io *io;
struct mesh_io_caps caps;
@@ -91,21 +113,70 @@ static void start_io(struct bt_mesh *mesh, uint16_t index)
io = mesh_io_new(index, MESH_IO_TYPE_GENERIC);
if (!io) {
l_error("Failed to start mesh io (hci %u)", index);
- current = NULL;
return;
}
mesh_io_get_caps(io, &caps);
- mesh->max_filters = caps.max_num_filters;
+ mesh.max_filters = caps.max_num_filters;
+
+ mesh.io = io;
+
+ l_debug("Started mesh (io %p) on hci %u", mesh.io, index);
+
+ node_attach_io(io);
+}
+
+/* Used for any outbound traffic that doesn't have Friendship Constraints */
+/* This includes Beacons, Provisioning and unrestricted Network Traffic */
+bool mesh_send_pkt(uint8_t count, uint16_t interval,
+ uint8_t *data, uint16_t len)
+{
+ struct mesh_io_send_info info = {
+ .type = MESH_IO_TIMING_TYPE_GENERAL,
+ .u.gen.cnt = count,
+ .u.gen.interval = interval,
+ .u.gen.max_delay = 0,
+ .u.gen.min_delay = 0,
+ };
+
+ return mesh_io_send(mesh.io, &info, data, len);
+}
+
+bool mesh_send_cancel(const uint8_t *filter, uint8_t len)
+{
+ return mesh_io_send_cancel(mesh.io, filter, len);
+}
- mesh_net_attach(mesh->net, io);
- mesh_net_set_window_accuracy(mesh->net, caps.window_accuracy);
- mesh->io = io;
- mesh->index = index;
+static void prov_rx(void *user_data, struct mesh_io_recv_info *info,
+ const uint8_t *data, uint16_t len)
+{
+ if (user_data != &mesh)
+ return;
+
+ if (mesh.prov_rx)
+ mesh.prov_rx(mesh.prov_data, data, len);
+}
+
+bool mesh_reg_prov_rx(prov_rx_cb_t cb, void *user_data)
+{
+ if (mesh.prov_rx && mesh.prov_rx != cb)
+ return false;
- current = NULL;
+ mesh.prov_rx = cb;
+ mesh.prov_data = user_data;
- l_debug("Started mesh (io %p) on hci %u", mesh->io, index);
+ return mesh_io_register_recv_cb(mesh.io, MESH_IO_FILTER_PROV,
+ prov_rx, &mesh);
+}
+
+void mesh_unreg_prov_rx(prov_rx_cb_t cb)
+{
+ if (mesh.prov_rx != cb)
+ return;
+
+ mesh.prov_rx = NULL;
+ mesh.prov_data = NULL;
+ mesh_io_deregister_recv_cb(mesh.io, MESH_IO_FILTER_PROV);
}
static void read_info_cb(uint8_t status, uint16_t length,
@@ -115,7 +186,7 @@ static void read_info_cb(uint8_t status, uint16_t length,
const struct mgmt_rp_read_info *rp = param;
uint32_t current_settings, supported_settings;
- if (!current)
+ if (mesh.io)
/* Already initialized */
return;
@@ -148,7 +219,7 @@ static void read_info_cb(uint8_t status, uint16_t length,
return;
}
- start_io(current, index);
+ start_io(index);
}
static void index_added(uint16_t index, uint16_t length, const void *param,
@@ -156,11 +227,8 @@ static void index_added(uint16_t index, uint16_t length, const void *param,
{
l_debug("hci device %u", index);
- if (!current)
- return;
-
- if (current->req_index != MGMT_INDEX_NONE &&
- index != current->req_index) {
+ if (mesh.req_index != MGMT_INDEX_NONE &&
+ index != mesh.req_index) {
l_debug("Ignore index %d", index);
return;
}
@@ -219,145 +287,100 @@ static void read_index_list_cb(uint8_t status, uint16_t length,
}
}
-static bool load_config(struct bt_mesh *mesh, const char *in_config_name)
+static bool init_mgmt(void)
{
- if (!mesh->net)
- return false;
-
- if (!storage_parse_config(mesh->net, in_config_name))
+ mgmt_mesh = mgmt_new_default();
+ if (!mgmt_mesh)
return false;
- /* Register foundational models */
- mesh_config_srv_init(mesh->net, PRIMARY_ELE_IDX);
-
- return true;
-}
-
-static bool init_mesh(void)
-{
- if (initialized)
- return true;
-
controllers = l_queue_new();
if (!controllers)
return false;
- mesh_list = l_queue_new();
- if (!mesh_list)
- return false;
-
- mgmt_mesh = mgmt_new_default();
- if (!mgmt_mesh)
- goto fail;
-
mgmt_register(mgmt_mesh, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
index_added, NULL, NULL);
mgmt_register(mgmt_mesh, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
index_removed, NULL, NULL);
-
- initialized = true;
return true;
-
-fail:
- l_error("Failed to initialize mesh management");
-
- l_queue_destroy(controllers, NULL);
-
- return false;
}
-struct bt_mesh *mesh_new(uint16_t index, const char *config_file)
+bool mesh_init(uint16_t index, const char *config_dir)
{
- struct bt_mesh *mesh;
+ if (initialized)
+ return true;
+
+ if (!init_mgmt()) {
+ l_error("Failed to initialize mesh management");
+ return false;
+ }
- if (!init_mesh())
- return NULL;
+ mesh.req_index = index;
- mesh = l_new(struct bt_mesh, 1);
- if (!mesh)
- return NULL;
+ mesh_model_init();
+ mesh_agent_init();
- mesh->req_index = index;
- mesh->index = MGMT_INDEX_NONE;
+ /* TODO: read mesh.conf */
+ mesh.prov_timeout = DEFAULT_PROV_TIMEOUT;
+ mesh.algorithms = DEFAULT_ALGORITHMS;
- mesh->net = mesh_net_new(index);
- if (!mesh->net) {
- l_free(mesh);
- return NULL;
- }
+ if (!config_dir)
+ config_dir = MESH_STORAGEDIR;
- if (!load_config(mesh, config_file)) {
- l_error("Failed to load mesh configuration: %s", config_file);
- l_free(mesh);
- return NULL;
- }
+ l_info("Loading node configuration from %s", config_dir);
+
+ if (!storage_load_nodes(config_dir))
+ return false;
- /*
- * TODO: Check if another mesh is searching for io.
- * If so, add to pending list and return.
- */
l_debug("send read index_list");
if (mgmt_send(mgmt_mesh, MGMT_OP_READ_INDEX_LIST,
MGMT_INDEX_NONE, 0, NULL,
- read_index_list_cb, mesh, NULL) > 0) {
- current = mesh;
- l_queue_push_tail(mesh_list, mesh);
- return mesh_ref(mesh);
- }
-
- l_free(mesh);
+ read_index_list_cb, NULL, NULL) <= 0)
+ return false;
- return NULL;
+ return true;
}
-struct bt_mesh *mesh_ref(struct bt_mesh *mesh)
+static void attach_exit(void *data)
{
- if (!mesh)
- return NULL;
-
- __sync_fetch_and_add(&mesh->ref_count, 1);
+ struct l_dbus_message *reply;
+ struct attach_data *pending = data;
- return mesh;
+ reply = dbus_error(pending->msg, MESH_ERROR_FAILED, "Failed. Exiting");
+ l_dbus_send(dbus_get_bus(), reply);
+ l_free(pending);
}
-void mesh_unref(struct bt_mesh *mesh)
+void mesh_cleanup(void)
{
- struct mesh_io *io;
+ struct l_dbus_message *reply;
- if (!mesh)
- return;
+ mesh_io_destroy(mesh.io);
+ mgmt_unref(mgmt_mesh);
- if (__sync_sub_and_fetch(&mesh->ref_count, 1))
- return;
+ if (join_pending) {
+ reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED,
+ "Failed. Exiting");
+ l_dbus_send(dbus_get_bus(), reply);
- if (mesh_net_provisioned_get(mesh->net))
- save_exit_config(mesh);
+ if (join_pending->disc_watch)
+ dbus_disconnect_watch_remove(dbus_get_bus(),
+ join_pending->disc_watch);
- node_cleanup(mesh->net);
+ if (join_pending->node)
+ node_free(join_pending->node);
- storage_release(mesh->net);
- io = mesh_net_detach(mesh->net);
- if (io)
- mesh_io_destroy(io);
+ l_free(join_pending);
+ join_pending = NULL;
+ }
- mesh_net_unref(mesh->net);
- l_queue_remove(mesh_list, mesh);
- l_free(mesh);
-}
+ l_queue_destroy(attach_queue, attach_exit);
+ node_cleanup_all();
+ mesh_model_cleanup();
-void mesh_cleanup(void)
-{
l_queue_destroy(controllers, NULL);
- l_queue_destroy(mesh_list, NULL);
- mgmt_unref(mgmt_mesh);
-}
-
-bool mesh_set_output(struct bt_mesh *mesh, const char *config_name)
-{
- if (!config_name)
- return false;
-
- return mesh_net_cfg_file_set(mesh->net, config_name);
+ l_dbus_object_remove_interface(dbus_get_bus(), BLUEZ_MESH_PATH,
+ MESH_NETWORK_INTERFACE);
+ l_dbus_unregister_interface(dbus_get_bus(), MESH_NETWORK_INTERFACE);
}
const char *mesh_status_str(uint8_t err)
@@ -386,7 +409,333 @@ const char *mesh_status_str(uint8_t err)
}
}
-struct mesh_net *mesh_get_net(struct bt_mesh *mesh)
+static void free_pending_join_call(bool failed)
+{
+ if (!join_pending)
+ return;
+
+ if (join_pending->disc_watch)
+ dbus_disconnect_watch_remove(dbus_get_bus(),
+ join_pending->disc_watch);
+
+ mesh_agent_remove(join_pending->agent);
+
+ if (failed) {
+ storage_remove_node_config(join_pending->node);
+ mesh_agent_remove(join_pending->agent);
+ }
+
+ l_free(join_pending);
+ join_pending = NULL;
+}
+
+/* This is being called if the app exits unexpectedly */
+static void prov_disc_cb(struct l_dbus *bus, void *user_data)
+{
+ if (!join_pending)
+ return;
+
+ if (join_pending->msg)
+ l_dbus_message_unref(join_pending->msg);
+
+ acceptor_cancel(&mesh);
+
+ join_pending->disc_watch = 0;
+
+ free_pending_join_call(true);
+}
+
+static const char *prov_status_str(uint8_t status)
+{
+ switch (status) {
+ case PROV_ERR_SUCCESS:
+ return "success";
+ case PROV_ERR_INVALID_PDU:
+ case PROV_ERR_INVALID_FORMAT:
+ case PROV_ERR_UNEXPECTED_PDU:
+ return "bad-pdu";
+ case PROV_ERR_CONFIRM_FAILED:
+ return "confirmation-failed";
+ case PROV_ERR_INSUF_RESOURCE:
+ return "out-of-resources";
+ case PROV_ERR_DECRYPT_FAILED:
+ return "decryption-error";
+ case PROV_ERR_CANT_ASSIGN_ADDR:
+ return "cannot-assign-addresses";
+ case PROV_ERR_TIMEOUT:
+ return "timeout";
+ case PROV_ERR_UNEXPECTED_ERR:
+ default:
+ return "unexpected-error";
+ }
+}
+
+static void send_join_failed(const char *owner, const char *path,
+ uint8_t status)
+{
+ struct l_dbus_message *msg;
+ struct l_dbus *dbus = dbus_get_bus();
+
+ msg = l_dbus_message_new_method_call(dbus, owner, path,
+ MESH_APPLICATION_INTERFACE,
+ "JoinFailed");
+
+ l_dbus_message_set_arguments(msg, "s", prov_status_str(status));
+ l_dbus_send(dbus_get_bus(), msg);
+
+ free_pending_join_call(true);
+}
+
+static bool prov_complete_cb(void *user_data, uint8_t status,
+ struct mesh_prov_node_info *info)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ const char *owner;
+ const char *path;
+ const uint8_t *dev_key;
+
+ l_debug("Provisioning complete %s", prov_status_str(status));
+
+ if (!join_pending)
+ return false;
+
+ owner = join_pending->sender;
+ path = join_pending->app_path;
+
+ if (status == PROV_ERR_SUCCESS &&
+ !node_add_pending_local(join_pending->node, info, mesh.io))
+ status = PROV_ERR_UNEXPECTED_ERR;
+
+ if (status != PROV_ERR_SUCCESS) {
+ send_join_failed(owner, path, status);
+ return false;
+ }
+
+ dev_key = node_get_device_key(join_pending->node);
+
+ msg = l_dbus_message_new_method_call(dbus, owner, path,
+ MESH_APPLICATION_INTERFACE,
+ "JoinComplete");
+
+ l_dbus_message_set_arguments(msg, "t", l_get_u64(dev_key));
+
+ l_dbus_send(dbus_get_bus(), msg);
+
+ free_pending_join_call(false);
+
+ return true;
+}
+
+static void node_init_cb(struct mesh_node *node, struct mesh_agent *agent)
+{
+ struct l_dbus_message *reply;
+ uint8_t num_ele;
+
+ if (!node) {
+ reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED,
+ "Failed to create node from application");
+ goto fail;
+ }
+
+ join_pending->node = node;
+ num_ele = node_get_num_elements(node);
+
+ if (!acceptor_start(num_ele, join_pending->uuid, mesh.algorithms,
+ mesh.prov_timeout, agent, prov_complete_cb,
+ &mesh))
+ {
+ reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED,
+ "Failed to start provisioning acceptor");
+ goto fail;
+ }
+
+ reply = l_dbus_message_new_method_return(join_pending->msg);
+ l_dbus_send(dbus_get_bus(), reply);
+ join_pending->msg = NULL;
+
+ return;
+
+fail:
+ l_dbus_send(dbus_get_bus(), reply);
+ mesh_agent_remove(join_pending->agent);
+ l_free(join_pending);
+ join_pending = NULL;
+}
+
+static struct l_dbus_message *join_network_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
{
- return mesh->net;
+ const char *app_path, *sender;
+ struct l_dbus_message_iter iter_uuid;
+ uint32_t n;
+
+ l_debug("Join network request");
+
+ if (join_pending)
+ return dbus_error(msg, MESH_ERROR_BUSY,
+ "Provisioning in progress");
+
+ if (!l_dbus_message_get_arguments(msg, "oay", &app_path,
+ &iter_uuid))
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+ join_pending = l_new(struct join_data, 1);
+
+ n = dbus_get_byte_array(&iter_uuid, join_pending->uuid,16);
+
+ if (n != 16) {
+ l_free(join_pending);
+ join_pending = NULL;
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS,
+ "Bad device UUID");
+ }
+
+ sender = l_dbus_message_get_sender(msg);
+
+ join_pending->sender = l_strdup(sender);
+ join_pending->disc_watch = dbus_disconnect_watch_add(dbus, sender,
+ prov_disc_cb, NULL);
+ join_pending->msg = l_dbus_message_ref(msg);
+ join_pending->app_path = app_path;
+
+ /* Try to create a temporary node */
+ node_join(app_path, sender, join_pending->uuid, node_init_cb);
+
+ return NULL;
+}
+
+static struct l_dbus_message *cancel_join_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ struct l_dbus_message *reply;
+
+ l_debug("Cancel Join");
+
+ if (!join_pending) {
+ reply = dbus_error(msg, MESH_ERROR_DOES_NOT_EXIST,
+ "No join in progress");
+ goto done;
+ }
+
+ acceptor_cancel(&mesh);
+
+ /* Return error to the original Join call */
+ if (join_pending->msg) {
+ reply = dbus_error(join_pending->msg, MESH_ERROR_FAILED, NULL);
+ l_dbus_send(dbus_get_bus(), reply);
+ }
+
+ reply = l_dbus_message_new_method_return(msg);
+ l_dbus_message_set_arguments(reply, "");
+
+ free_pending_join_call(true);
+done:
+ return reply;
+}
+
+static bool match_attach_request(const void *a, const void *b)
+{
+ const struct attach_data *pending = a;
+ const uint64_t *token = b;
+
+ return *token == pending->token;
+}
+
+static void attach_ready_cb(int status, char *node_path, uint64_t token)
+{
+ struct l_dbus_message *reply;
+ struct attach_data *pending;
+
+ pending = l_queue_find(attach_queue, match_attach_request, &token);
+ if (!pending)
+ return;
+
+ if (status != MESH_ERROR_NONE) {
+ const char *desc = (status == MESH_ERROR_NOT_FOUND) ?
+ "Node match not found" : "Attach failed";
+ reply = dbus_error(pending->msg, status, desc);
+ goto done;
+ }
+
+ reply = l_dbus_message_new_method_return(pending->msg);
+
+ node_build_attach_reply(reply, token);
+
+done:
+ l_dbus_send(dbus_get_bus(), reply);
+ l_queue_remove(attach_queue, pending);
+ l_free(pending);
+}
+
+static struct l_dbus_message *attach_call(struct l_dbus *dbus,
+ struct l_dbus_message *msg,
+ void *user_data)
+{
+ uint64_t token = 1;
+ const char *app_path, *sender;
+ struct attach_data *pending;
+
+ l_debug("Attach");
+
+ if (!l_dbus_message_get_arguments(msg, "ot", &app_path, &token))
+ return dbus_error(msg, MESH_ERROR_INVALID_ARGS, NULL);
+
+ sender = l_dbus_message_get_sender(msg);
+
+ if (node_attach(app_path, sender, token, attach_ready_cb) !=
+ MESH_ERROR_NONE)
+ return dbus_error(msg, MESH_ERROR_NOT_FOUND,
+ "Matching node not found");
+
+ pending = l_new(struct attach_data, 1);
+
+ pending->token = token;
+ pending->msg = l_dbus_message_ref(msg);
+
+ if (!attach_queue)
+ attach_queue = l_queue_new();
+
+ l_queue_push_tail(attach_queue, pending);
+
+ return NULL;
+}
+
+static void setup_network_interface(struct l_dbus_interface *iface)
+{
+ l_dbus_interface_method(iface, "Join", 0, join_network_call, "",
+ "oay", "app", "uuid");
+
+ l_dbus_interface_method(iface, "Cancel", 0, cancel_join_call, "", "");
+
+ l_dbus_interface_method(iface, "Attach", 0, attach_call,
+ "oa(ya(qa{sv}))", "ot", "node", "configuration",
+ "app", "token");
+
+ /* TODO: Implement Leave method */
+}
+
+bool mesh_dbus_init(struct l_dbus *dbus)
+{
+ if (!l_dbus_register_interface(dbus, MESH_NETWORK_INTERFACE,
+ setup_network_interface,
+ NULL, false)) {
+ l_info("Unable to register %s interface",
+ MESH_NETWORK_INTERFACE);
+ return false;
+ }
+
+ if (!l_dbus_object_add_interface(dbus, BLUEZ_MESH_PATH,
+ MESH_NETWORK_INTERFACE, NULL)) {
+ l_info("Unable to register the mesh object on '%s'",
+ MESH_NETWORK_INTERFACE);
+ l_dbus_unregister_interface(dbus, MESH_NETWORK_INTERFACE);
+ return false;
+ }
+
+ l_info("Added Network Interface on %s", BLUEZ_MESH_PATH);
+
+ return true;
}
diff --git a/mesh/mesh.h b/mesh/mesh.h
index 8d389883b..1189f8276 100644
--- a/mesh/mesh.h
+++ b/mesh/mesh.h
@@ -18,15 +18,24 @@
*
*/
-struct bt_mesh;
-struct mesh_net;
+#define BLUEZ_MESH_NAME "org.bluez.mesh"
-struct bt_mesh *mesh_new(uint16_t index, const char *in_config_name);
-struct bt_mesh *mesh_ref(struct bt_mesh *mesh);
-void mesh_unref(struct bt_mesh *mesh);
-bool mesh_set_output(struct bt_mesh *mesh, const char *out_config_name);
+#define MESH_NETWORK_INTERFACE "org.bluez.mesh.Network1"
+#define MESH_NODE_INTERFACE "org.bluez.mesh.Node1"
+#define MESH_ELEMENT_INTERFACE "org.bluez.mesh.Element1"
+#define MESH_APPLICATION_INTERFACE "org.bluez.mesh.Application1"
+#define MESH_PROVISION_AGENT_INTERFACE "org.bluez.mesh.ProvisionAgent1"
+#define ERROR_INTERFACE "org.bluez.mesh.Error"
+
+typedef void (*prov_rx_cb_t)(void *user_data, const uint8_t *data,
+ uint16_t len);
+bool mesh_init(uint16_t index, const char *in_config_name);
void mesh_cleanup(void);
-const char *mesh_status_str(uint8_t err);
+bool mesh_dbus_init(struct l_dbus *dbus);
-/* Command line testing */
-struct mesh_net *mesh_get_net(struct bt_mesh *mesh);
+const char *mesh_status_str(uint8_t err);
+bool mesh_send_pkt(uint8_t count, uint16_t interval, uint8_t *data,
+ uint16_t len);
+bool mesh_send_cancel(const uint8_t *filter, uint8_t len);
+bool mesh_reg_prov_rx(prov_rx_cb_t cb, void *user_data);
+void mesh_unreg_prov_rx(prov_rx_cb_t cb);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 16/30] mesh: Make config model handle multiple nodes
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (14 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 15/30] mesh: Re-architect " Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 17/30] mesh: Multi node Config Server model Brian Gix
` (13 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/cfgmod.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mesh/cfgmod.h b/mesh/cfgmod.h
index bedb0c6f6..c849923ca 100644
--- a/mesh/cfgmod.h
+++ b/mesh/cfgmod.h
@@ -95,4 +95,4 @@
#define OP_VEND_MODEL_APP_GET 0x804C
#define OP_VEND_MODEL_APP_LIST 0x804E
-void mesh_config_srv_init(struct mesh_net *net, uint8_t ele_idx);
+void mesh_config_srv_init(struct mesh_node *node, uint8_t ele_idx);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 17/30] mesh: Multi node Config Server model
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (15 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 16/30] mesh: Make config model handle multiple nodes Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 18/30] mesh: restructure I/O for multiple nodes Brian Gix
` (12 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/cfgmod-server.c | 173 ++++++++++++++++++++++++++-------------------------
1 file changed, 88 insertions(+), 85 deletions(-)
diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c
index 2c4a02912..6cddb8eac 100644
--- a/mesh/cfgmod-server.c
+++ b/mesh/cfgmod-server.c
@@ -40,7 +40,7 @@
#define CFG_MAX_MSG_LEN 380
-static void send_pub_status(struct mesh_net *net, uint16_t src, uint16_t dst,
+static void send_pub_status(struct mesh_node *node, uint16_t src, uint16_t dst,
uint8_t status, uint16_t ele_addr, uint16_t pub_addr,
uint32_t mod_id, uint16_t idx, bool cred_flag,
uint8_t ttl, uint8_t period, uint8_t retransmit)
@@ -60,7 +60,7 @@ static void send_pub_status(struct mesh_net *net, uint16_t src, uint16_t dst,
msg[n++] = ttl;
msg[n++] = period;
msg[n++] = retransmit;
- if (mod_id < 0x10000) {
+ if (mod_id < 0x10000 || mod_id > VENDOR_ID_MASK) {
l_put_le16(mod_id, msg + n);
n += 2;
} else {
@@ -70,12 +70,11 @@ static void send_pub_status(struct mesh_net *net, uint16_t src, uint16_t dst,
n += 2;
}
- mesh_model_send(net, CONFIG_SRV_MODEL,
- dst, src,
+ mesh_model_send(node, dst, src,
APP_IDX_DEV, DEFAULT_TTL, msg, n);
}
-static bool config_pub_get(struct mesh_net *net, uint16_t src, uint16_t dst,
+static bool config_pub_get(struct mesh_node *node, uint16_t src, uint16_t dst,
const uint8_t *pkt, uint16_t size)
{
uint32_t mod_id;
@@ -84,33 +83,34 @@ static bool config_pub_get(struct mesh_net *net, uint16_t src, uint16_t dst,
struct mesh_model_pub *pub = NULL;
int status;
- if (size == 4)
+ if (size == 4) {
mod_id = l_get_le16(pkt + 2);
- else if (size == 6) {
+ mod_id |= VENDOR_ID_MASK;
+ } else if (size == 6) {
mod_id = l_get_le16(pkt + 2) << 16;
mod_id |= l_get_le16(pkt + 4);
} else
return false;
ele_addr = l_get_le16(pkt);
- ele_idx = node_get_element_idx(mesh_net_local_node_get(net), ele_addr);
+ ele_idx = node_get_element_idx(node, ele_addr);
if (ele_idx >= 0)
- pub = mesh_model_pub_get(net, ele_idx, mod_id, &status);
+ pub = mesh_model_pub_get(node, ele_idx, mod_id, &status);
else
status = MESH_STATUS_INVALID_ADDRESS;
if (pub && status == MESH_STATUS_SUCCESS)
- send_pub_status(net, src, dst, status, ele_addr, pub->addr,
+ send_pub_status(node, src, dst, status, ele_addr, pub->addr,
mod_id, pub->idx, pub->credential, pub->ttl,
pub->period, pub->retransmit);
else
- send_pub_status(net, src, dst, status, ele_addr, 0, mod_id,
+ send_pub_status(node, src, dst, status, ele_addr, 0, mod_id,
0, 0, 0, 0, 0);
return true;
}
-static bool config_pub_set(struct mesh_net *net, uint16_t src, uint16_t dst,
+static bool config_pub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
const uint8_t *pkt, uint16_t size,
bool unreliable)
{
@@ -133,6 +133,7 @@ static bool config_pub_set(struct mesh_net *net, uint16_t src, uint16_t dst,
period = pkt[7];
retransmit = pkt[8];
mod_id = l_get_le16(pkt + 9);
+ mod_id |= VENDOR_ID_MASK;
break;
case 13:
@@ -151,6 +152,7 @@ static bool config_pub_set(struct mesh_net *net, uint16_t src, uint16_t dst,
period = pkt[21];
retransmit = pkt[22];
mod_id = l_get_le16(pkt + 23);
+ mod_id |= VENDOR_ID_MASK;
break;
case 27:
@@ -181,24 +183,24 @@ static bool config_pub_set(struct mesh_net *net, uint16_t src, uint16_t dst,
if (!b_virt && test_addr > 0x7fff && test_addr < 0xc000)
return false;
- status = mesh_model_pub_set(net, ele_addr, mod_id, pub_addr, idx,
+ status = mesh_model_pub_set(node, ele_addr, mod_id, pub_addr, idx,
cred_flag, ttl, period, retransmit,
b_virt, &ota);
- l_info("pub_set: status %d, ea %4.4x, ota: %4.4x, mod: %x, idx: %3.3x",
+ l_debug("pub_set: status %d, ea %4.4x, ota: %4.4x, mod: %x, idx: %3.3x",
status, ele_addr, ota, mod_id, idx);
if (IS_UNASSIGNED(ota) && !b_virt)
ttl = period = idx = 0;
if (status >= 0 && !unreliable)
- send_pub_status(net, src, dst, status, ele_addr, ota,
+ send_pub_status(node, src, dst, status, ele_addr, ota,
mod_id, idx, cred_flag, ttl, period,
retransmit);
return true;
}
-static void send_sub_status(struct mesh_net *net, uint16_t src, uint16_t dst,
+static void send_sub_status(struct mesh_node *node, uint16_t src, uint16_t dst,
uint8_t status, uint16_t ele_addr,
uint16_t addr, uint32_t mod)
{
@@ -210,7 +212,7 @@ static void send_sub_status(struct mesh_net *net, uint16_t src, uint16_t dst,
n += 2;
l_put_le16(addr, msg + n);
n += 2;
- if (mod >= 0x10000) {
+ if (mod >= 0x10000 && mod < VENDOR_ID_MASK) {
l_put_le16(mod >> 16, msg + n);
l_put_le16(mod, msg + n + 2);
n += 4;
@@ -219,11 +221,10 @@ static void send_sub_status(struct mesh_net *net, uint16_t src, uint16_t dst,
n += 2;
}
- mesh_model_send(net, CONFIG_SRV_MODEL, dst, src, APP_IDX_DEV,
- DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL, msg, n);
}
-static bool config_sub_get(struct mesh_net *net, uint16_t src, uint16_t dst,
+static bool config_sub_get(struct mesh_node *node, uint16_t src, uint16_t dst,
const uint8_t *pkt, uint16_t size)
{
uint16_t ele_addr;
@@ -251,6 +252,7 @@ static bool config_sub_get(struct mesh_net *net, uint16_t src, uint16_t dst,
n += 2;
l_put_le16(mod_id, msg + n);
n += 2;
+ mod_id |= VENDOR_ID_MASK;
break;
case 6:
@@ -269,7 +271,7 @@ static bool config_sub_get(struct mesh_net *net, uint16_t src, uint16_t dst,
}
buf_size = sizeof(uint16_t) * MAX_GRP_PER_MOD;
- ret = mesh_model_sub_get(net, ele_addr, mod_id, msg + n, buf_size,
+ ret = mesh_model_sub_get(node, ele_addr, mod_id, msg + n, buf_size,
&size);
if (!ret)
@@ -277,13 +279,11 @@ static bool config_sub_get(struct mesh_net *net, uint16_t src, uint16_t dst,
else if (ret > 0)
*status = ret;
- mesh_model_send(net, CONFIG_SRV_MODEL,
- dst, src, APP_IDX_DEV,
- DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL, msg, n);
return true;
}
-static void config_sub_set(struct mesh_net *net, uint16_t src, uint16_t dst,
+static void config_sub_set(struct mesh_node *node, uint16_t src, uint16_t dst,
const uint8_t *pkt, uint16_t size,
bool virt, uint32_t opcode)
{
@@ -301,13 +301,15 @@ static void config_sub_set(struct mesh_net *net, uint16_t src, uint16_t dst,
if (opcode != OP_CONFIG_MODEL_SUB_DELETE_ALL)
return;
mod_id = l_get_le16(pkt + 2);
+ mod_id |= VENDOR_ID_MASK;
break;
case 6:
if (virt)
return;
- if (opcode != OP_CONFIG_MODEL_SUB_DELETE_ALL)
+ if (opcode != OP_CONFIG_MODEL_SUB_DELETE_ALL) {
mod_id = l_get_le16(pkt + 4);
- else {
+ mod_id |= VENDOR_ID_MASK;
+ } else {
mod_id = l_get_le16(pkt + 2) << 16;
mod_id |= l_get_le16(pkt + 4);
}
@@ -322,6 +324,7 @@ static void config_sub_set(struct mesh_net *net, uint16_t src, uint16_t dst,
if (!virt)
return;
mod_id = l_get_le16(pkt + 18);
+ mod_id |= VENDOR_ID_MASK;
break;
case 22:
if (!virt)
@@ -341,42 +344,42 @@ static void config_sub_set(struct mesh_net *net, uint16_t src, uint16_t dst,
func = opcode & ~OP_UNRELIABLE;
switch (func) {
default:
- l_info("Bad opcode: %x", func);
+ l_debug("Bad opcode: %x", func);
return;
case OP_CONFIG_MODEL_SUB_DELETE_ALL:
- status = mesh_model_sub_del_all(net, ele_addr, mod_id);
+ status = mesh_model_sub_del_all(node, ele_addr, mod_id);
break;
case OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE:
grp = UNASSIGNED_ADDRESS;
/* Fall Through */
case OP_CONFIG_MODEL_SUB_OVERWRITE:
- status = mesh_model_sub_ovr(net, ele_addr, mod_id,
+ status = mesh_model_sub_ovr(node, ele_addr, mod_id,
addr, virt, &grp);
break;
case OP_CONFIG_MODEL_SUB_VIRT_ADD:
grp = UNASSIGNED_ADDRESS;
/* Fall Through */
case OP_CONFIG_MODEL_SUB_ADD:
- status = mesh_model_sub_add(net, ele_addr, mod_id,
+ status = mesh_model_sub_add(node, ele_addr, mod_id,
addr, virt, &grp);
break;
case OP_CONFIG_MODEL_SUB_VIRT_DELETE:
grp = UNASSIGNED_ADDRESS;
/* Fall Through */
case OP_CONFIG_MODEL_SUB_DELETE:
- status = mesh_model_sub_del(net, ele_addr, mod_id,
+ status = mesh_model_sub_del(node, ele_addr, mod_id,
addr, virt, &grp);
break;
}
if (!unreliable && status >= 0)
- send_sub_status(net, src, dst, status, ele_addr, grp, mod_id);
+ send_sub_status(node, src, dst, status, ele_addr, grp, mod_id);
}
-static void send_model_app_status(struct mesh_net *net, uint16_t src,
+static void send_model_app_status(struct mesh_node *node, uint16_t src,
uint16_t dst, uint8_t status,
uint16_t addr, uint32_t id,
uint16_t idx)
@@ -389,18 +392,17 @@ static void send_model_app_status(struct mesh_net *net, uint16_t src,
n += 2;
l_put_le16(idx, msg + n);
n += 2;
- if (id > 0xffff) {
+ if (id >= 0x10000 && id < VENDOR_ID_MASK) {
l_put_le16(id >> 16, msg + n);
n += 2;
}
l_put_le16(id, msg + n);
n += 2;
- mesh_model_send(net, CONFIG_SRV_MODEL, dst, src, APP_IDX_DEV,
- DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL, msg, n);
}
-static void model_app_list(struct mesh_net *net, uint16_t src, uint16_t dst,
+static void model_app_list(struct mesh_node *node, uint16_t src, uint16_t dst,
const uint8_t *pkt, uint16_t size)
{
uint16_t ele_addr;
@@ -427,6 +429,7 @@ static void model_app_list(struct mesh_net *net, uint16_t src, uint16_t dst,
mod_id = l_get_le16(pkt + 2);
l_put_le16(ele_addr, msg + 1 + n);
l_put_le16(mod_id, msg + 3 + n);
+ mod_id |= VENDOR_ID_MASK;
n += 5;
break;
case 6:
@@ -443,20 +446,20 @@ static void model_app_list(struct mesh_net *net, uint16_t src, uint16_t dst,
}
- result = mesh_model_get_bindings(net, ele_addr, mod_id, msg + n,
+ result = mesh_model_get_bindings(node, ele_addr, mod_id, msg + n,
buf_size, &size);
n += size;
if (result >= 0) {
*status = result;
- mesh_model_send(net, CONFIG_SRV_MODEL, dst, src, APP_IDX_DEV,
- DEFAULT_TTL, msg, n);
+ mesh_model_send(node, dst, src, APP_IDX_DEV, DEFAULT_TTL,
+ msg, n);
}
l_free(msg);
}
-static bool model_app_bind(struct mesh_net *net, uint16_t src, uint16_t dst,
+static bool model_app_bind(struct mesh_node *node, uint16_t src, uint16_t dst,
const uint8_t *pkt, uint16_t size,
bool unbind)
{
@@ -471,6 +474,7 @@ static bool model_app_bind(struct mesh_net *net, uint16_t src, uint16_t dst,
case 6:
mod_id = l_get_le16(pkt + 4);
+ mod_id |= VENDOR_ID_MASK;
break;
case 8:
mod_id = l_get_le16(pkt + 4) << 16;
@@ -485,11 +489,11 @@ static bool model_app_bind(struct mesh_net *net, uint16_t src, uint16_t dst,
return false;
if (unbind)
- result = mesh_model_binding_del(net, ele_addr, mod_id, idx);
+ result = mesh_model_binding_del(node, ele_addr, mod_id, idx);
else
- result = mesh_model_binding_add(net, ele_addr, mod_id, idx);
+ result = mesh_model_binding_add(node, ele_addr, mod_id, idx);
- send_model_app_status(net, src, dst, result, ele_addr, mod_id, idx);
+ send_model_app_status(node, src, dst, result, ele_addr, mod_id, idx);
return true;
}
@@ -533,7 +537,7 @@ static void hb_sub_timeout_func(struct l_timeout *timeout, void *user_data)
struct mesh_net *net = user_data;
struct mesh_net_heartbeat *hb = mesh_net_heartbeat_get(net);
- l_info("HB Subscription Ended");
+ l_debug("HB Subscription Ended");
l_timeout_remove(hb->sub_timer);
hb->sub_timer = NULL;
hb->sub_enabled = false;
@@ -639,7 +643,7 @@ static int hb_subscription_set(struct mesh_net *net, uint16_t src,
static void node_reset(struct l_timeout *timeout, void *user_data)
{
- l_info("Node Reset");
+ l_debug("Node Reset");
l_timeout_remove(timeout);
l_main_quit();
}
@@ -649,7 +653,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
const uint8_t *data, uint16_t size,
uint8_t ttl, const void *user_data)
{
- struct mesh_net *net = (struct mesh_net *) user_data;
+ struct mesh_node *node = (struct mesh_node *) user_data;
+ struct mesh_net *net = node_get_net(node);
const uint8_t *pkt = data;
struct timeval time_now;
uint32_t opcode, tmp32;
@@ -663,7 +668,6 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
bool virt = false;
uint8_t count;
uint16_t interval;
- struct mesh_node *node;
uint16_t n;
if (idx != APP_IDX_DEV)
@@ -675,10 +679,10 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
} else
return false;
+ net = node_get_net(node);
hb = mesh_net_heartbeat_get(net);
l_debug("CONFIG-SRV-opcode 0x%x size %u idx %3.3x", opcode, size, idx);
- node = mesh_net_local_node_get(net);
n = 0;
switch (opcode) {
@@ -691,8 +695,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
/* Only page 0 is currently supported */
if (pkt[0] != 0) {
- l_info("Unsupported page number %d", pkt[0]);
- l_info("Returning page number 0");
+ l_debug("Unsupported page number %d", pkt[0]);
+ l_debug("Returning page number 0");
}
long_msg = l_malloc(CFG_MAX_MSG_LEN);
n = mesh_model_opcode_set(OP_DEV_COMP_STATUS, long_msg);
@@ -711,7 +715,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
/* Fall Through */
case OP_CONFIG_DEFAULT_TTL_GET:
- l_info("Get/Set Default TTL");
+ l_debug("Get/Set Default TTL");
n = mesh_model_opcode_set(OP_CONFIG_DEFAULT_TTL_STATUS, msg);
msg[n++] = node_default_ttl_get(node);
@@ -721,7 +725,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
if (size != 25 && size != 27)
return true;
- config_pub_set(net, src, unicast, pkt, size,
+ config_pub_set(node, src, unicast, pkt, size,
!!(opcode & OP_UNRELIABLE));
break;
@@ -729,24 +733,24 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
if (size != 11 && size != 13)
return true;
- config_pub_set(net, src, unicast, pkt, size,
+ config_pub_set(node, src, unicast, pkt, size,
!!(opcode & OP_UNRELIABLE));
break;
case OP_CONFIG_MODEL_PUB_GET:
- config_pub_get(net, src, unicast, pkt, size);
+ config_pub_get(node, src, unicast, pkt, size);
break;
case OP_CONFIG_VEND_MODEL_SUB_GET:
if (size != 6)
return true;
- config_sub_get(net, src, unicast, pkt, size);
+ config_sub_get(node, src, unicast, pkt, size);
break;
case OP_CONFIG_MODEL_SUB_GET:
if (size != 4)
return true;
- config_sub_get(net, src, unicast, pkt, size);
+ config_sub_get(node, src, unicast, pkt, size);
break;
case OP_CONFIG_MODEL_SUB_VIRT_OVERWRITE:
@@ -758,7 +762,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
case OP_CONFIG_MODEL_SUB_DELETE:
case OP_CONFIG_MODEL_SUB_ADD:
case OP_CONFIG_MODEL_SUB_DELETE_ALL:
- config_sub_set(net, src, unicast, pkt, size, virt, opcode);
+ config_sub_set(node, src, unicast, pkt, size, virt, opcode);
break;
case OP_CONFIG_RELAY_SET:
@@ -777,7 +781,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
msg[n++] = node_relay_mode_get(node, &count, &interval);
msg[n++] = ((count - 1) << 5) + ((interval/10 - 1) & 0x1f);
- l_info("Get/Set Relay Config (%d)", msg[n-1]);
+ l_debug("Get/Set Relay Config (%d)", msg[n-1]);
break;
case OP_CONFIG_NETWORK_TRANSMIT_SET:
@@ -786,7 +790,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
count = (pkt[0] >> 5) + 1;
interval = ((pkt[0] & 0x1f) + 1) * 10;
- if (storage_local_set_transmit_params(net, count, interval))
+ if (storage_set_transmit_params(node_jconfig_get(node), count,
+ interval))
mesh_net_transmit_params_set(net, count, interval);
/* Fall Through */
@@ -796,7 +801,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
mesh_net_transmit_params_get(net, &count, &interval);
msg[n++] = ((count - 1) << 5) + ((interval/10 - 1) & 0x1f);
- l_info("Get/Set Network Transmit Config");
+ l_debug("Get/Set Network Transmit Config");
break;
case OP_CONFIG_PROXY_SET:
@@ -810,7 +815,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
n = mesh_model_opcode_set(OP_CONFIG_PROXY_STATUS, msg);
msg[n++] = node_proxy_mode_get(node);
- l_info("Get/Set Config Proxy (%d)", msg[n-1]);
+ l_debug("Get/Set Config Proxy (%d)", msg[n-1]);
break;
case OP_NODE_IDENTITY_SET:
@@ -845,7 +850,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
n += 2;
msg[n++] = state;
- l_info("Get/Set Config Identity (%d)", state);
+ l_debug("Get/Set Config Identity (%d)", state);
break;
case OP_CONFIG_BEACON_SET:
@@ -859,7 +864,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
n = mesh_model_opcode_set(OP_CONFIG_BEACON_STATUS, msg);
msg[n++] = node_beacon_mode_get(node);
- l_info("Get/Set Config Beacon (%d)", msg[n-1]);
+ l_debug("Get/Set Config Beacon (%d)", msg[n-1]);
break;
case OP_CONFIG_FRIEND_SET:
@@ -874,7 +879,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
n = mesh_model_opcode_set(OP_CONFIG_FRIEND_STATUS, msg);
msg[n++] = node_friend_mode_get(node);
- l_info("Get/Set Friend (%d)", msg[n-1]);
+ l_debug("Get/Set Friend (%d)", msg[n-1]);
break;
case OP_CONFIG_KEY_REFRESH_PHASE_SET:
@@ -908,7 +913,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
n += 2;
msg[n++] = phase;
- l_info("Get/Set Key Refresh State (%d)", msg[n-1]);
+ l_debug("Get/Set Key Refresh State (%d)", msg[n-1]);
break;
case OP_APPKEY_ADD:
@@ -921,7 +926,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
b_res = appkey_key_add(net, net_idx, app_idx, pkt + 3,
opcode == OP_APPKEY_UPDATE);
- l_info("Add/Update AppKey %s: Net_Idx %3.3x, App_Idx %3.3x",
+ l_debug("Add/Update AppKey %s: Net_Idx %3.3x, App_Idx %3.3x",
(b_res == MESH_STATUS_SUCCESS) ? "success" : "fail",
net_idx, app_idx);
@@ -942,9 +947,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
net_idx = l_get_le16(pkt) & 0xfff;
app_idx = l_get_le16(pkt + 1) >> 4;
b_res = appkey_key_delete(net, net_idx, app_idx);
- if (b_res == MESH_STATUS_SUCCESS)
- node_app_key_delete(net, dst, net_idx, app_idx);
- l_info("Delete AppKey %s Net_Idx %3.3x to App_Idx %3.3x",
+ l_debug("Delete AppKey %s Net_Idx %3.3x to App_Idx %3.3x",
(b_res == MESH_STATUS_SUCCESS) ? "success" : "fail",
net_idx, app_idx);
@@ -979,7 +982,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
b_res = mesh_net_add_key(net, opcode == OP_NETKEY_UPDATE,
l_get_le16(pkt), pkt + 2);
- l_info("NetKey Add/Update %s",
+ l_debug("NetKey Add/Update %s",
(b_res == MESH_STATUS_SUCCESS) ? "success" : "fail");
n = mesh_model_opcode_set(OP_NETKEY_STATUS, msg);
@@ -994,7 +997,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
b_res = mesh_net_del_key(net, l_get_le16(pkt));
- l_info("NetKey delete %s",
+ l_debug("NetKey delete %s",
(b_res == MESH_STATUS_SUCCESS) ? "success" : "fail");
n = mesh_model_opcode_set(OP_NETKEY_STATUS, msg);
@@ -1016,26 +1019,26 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
case OP_MODEL_APP_BIND:
case OP_MODEL_APP_UNBIND:
- model_app_bind(net, src, unicast, pkt, size,
+ model_app_bind(node, src, unicast, pkt, size,
opcode != OP_MODEL_APP_BIND);
break;
case OP_VEND_MODEL_APP_GET:
if (size != 6)
return true;
- model_app_list(net, src, unicast, pkt, size);
+ model_app_list(node, src, unicast, pkt, size);
break;
case OP_MODEL_APP_GET:
if (size != 4)
return true;
- model_app_list(net, src, unicast, pkt, size);
+ model_app_list(node, src, unicast, pkt, size);
break;
case OP_CONFIG_HEARTBEAT_PUB_SET:
- l_info("OP_CONFIG_HEARTBEAT_PUB_SET");
+ l_debug("OP_CONFIG_HEARTBEAT_PUB_SET");
if (size != 9) {
- l_info("bad size %d", size);
+ l_debug("bad size %d", size);
return true;
}
if (pkt[2] > 0x11 || pkt[3] > 0x10 || pkt[4] > 0x7f)
@@ -1101,7 +1104,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
if (size != 5)
return true;
- l_info("Set Sub Period (Log %2.2x) %d sec",
+ l_debug("Set Sub Period (Log %2.2x) %d sec",
pkt[4], log_to_uint32(pkt[4], 1));
b_res = hb_subscription_set(net, l_get_le16(pkt),
@@ -1121,7 +1124,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
else
time_now.tv_sec = hb->sub_period - time_now.tv_sec;
- l_info("Sub Period (Log %2.2x) %d sec",
+ l_debug("Sub Period (Log %2.2x) %d sec",
uint32_to_log(time_now.tv_sec),
(int) time_now.tv_sec);
@@ -1159,8 +1162,7 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
if (n) {
/* print_packet("App Tx", long_msg ? long_msg : msg, n); */
- mesh_model_send(net, CONFIG_SRV_MODEL,
- unicast, src,
+ mesh_model_send(node, unicast, src,
APP_IDX_DEV, DEFAULT_TTL,
long_msg ? long_msg : msg, n);
}
@@ -1171,7 +1173,8 @@ static bool cfg_srv_pkt(uint16_t src, uint32_t dst,
static void cfgmod_srv_unregister(void *user_data)
{
- struct mesh_net *net = user_data;
+ struct mesh_node *node = user_data;
+ struct mesh_net *net = node_get_net(node);
struct mesh_net_heartbeat *hb = mesh_net_heartbeat_get(net);
l_timeout_remove(hb->pub_timer);
@@ -1187,8 +1190,8 @@ static const struct mesh_model_ops ops = {
.pub = NULL
};
-void mesh_config_srv_init(struct mesh_net *net, uint8_t ele_idx)
+void mesh_config_srv_init(struct mesh_node *node, uint8_t ele_idx)
{
l_debug("%2.2x", ele_idx);
- mesh_model_register(net, ele_idx, CONFIG_SRV_MODEL, &ops, net);
+ mesh_model_register(node, ele_idx, CONFIG_SRV_MODEL, &ops, node);
}
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 18/30] mesh: restructure I/O for multiple nodes
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (16 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 17/30] mesh: Multi node Config Server model Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 19/30] mesh: Restrusture DB to support " Brian Gix
` (11 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/mesh-io.c | 3 ++-
mesh/mesh-io.h | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c
index 5cdfdc5ff..8cf6c486a 100644
--- a/mesh/mesh-io.c
+++ b/mesh/mesh-io.c
@@ -177,7 +177,8 @@ bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info,
return false;
}
-bool mesh_io_send_cancel(struct mesh_io *io, uint8_t *pattern, uint8_t len)
+bool mesh_io_send_cancel(struct mesh_io *io, const uint8_t *pattern,
+ uint8_t len)
{
io = l_queue_find(io_list, match_by_io, io);
diff --git a/mesh/mesh-io.h b/mesh/mesh-io.h
index 754f6129c..71d3cb980 100644
--- a/mesh/mesh-io.h
+++ b/mesh/mesh-io.h
@@ -96,4 +96,5 @@ bool mesh_set_filter(struct mesh_io *io, uint8_t filter_id,
bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info,
const uint8_t *data, uint16_t len);
-bool mesh_io_send_cancel(struct mesh_io *io, uint8_t *pattern, uint8_t len);
+bool mesh_io_send_cancel(struct mesh_io *io, const uint8_t *pattern,
+ uint8_t len);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 19/30] mesh: Restrusture DB to support multiple nodes
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (17 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 18/30] mesh: restructure I/O for multiple nodes Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 20/30] mesh: restructure model services for " Brian Gix
` (10 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/mesh-db.c | 454 +++++++++++++++++++++++++++++++++++++--------------------
mesh/mesh-db.h | 6 +-
2 files changed, 296 insertions(+), 164 deletions(-)
diff --git a/mesh/mesh-db.c b/mesh/mesh-db.c
index 86e17ed9a..01e1c479f 100644
--- a/mesh/mesh-db.c
+++ b/mesh/mesh-db.c
@@ -162,6 +162,7 @@ static json_object *jarray_string_del(json_object *jarray, char *str,
if (str_entry && !strncmp(str, str_entry, len))
continue;
+ json_object_get(jentry);
json_object_array_add(jarray_new, jentry);
}
@@ -193,9 +194,6 @@ static json_object *jarray_key_del(json_object *jarray, int16_t idx)
{
json_object *jarray_new;
int i, sz = json_object_array_length(jarray);
- char idx_str[5];
-
- snprintf(idx_str, 5, "%4.4x", idx);
jarray_new = json_object_new_array();
if (!jarray_new)
@@ -203,16 +201,17 @@ static json_object *jarray_key_del(json_object *jarray, int16_t idx)
for (i = 0; i < sz; ++i) {
json_object *jentry, *jvalue;
- char *str;
jentry = json_object_array_get_idx(jarray, i);
if (json_object_object_get_ex(jentry, "index", &jvalue)) {
- str = (char *)json_object_get_string(jvalue);
- if (str && !strncmp(str, idx_str, 4))
+ int tmp = json_object_get_int(jvalue);
+
+ if (tmp == idx)
continue;
}
+ json_object_get(jentry);
json_object_array_add(jarray_new, jentry);
}
@@ -389,19 +388,10 @@ bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,
char buf[5];
json_object_object_get_ex(jobj, "netKeys", &jarray);
- if (!jarray && (phase != KEY_REFRESH_PHASE_NONE))
- return false;
if (jarray)
jentry = get_key_object(jarray, idx);
- /*
- * The key entry should exist if the key is updated
- * (i.e., Key Refresh is underway)
- */
- if (!jentry && (phase != KEY_REFRESH_PHASE_NONE))
- return false;
-
if (jentry) {
uint8_t buf[16];
json_object *jvalue;
@@ -422,7 +412,7 @@ bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,
return false;
}
- if (phase == KEY_REFRESH_PHASE_NONE) {
+ if (!jentry) {
jentry = json_object_new_object();
if (!jentry)
goto fail;
@@ -442,6 +432,19 @@ bool mesh_db_net_key_add(json_object *jobj, uint16_t idx,
if (!add_key(jentry, "key", key))
goto fail;
+ /* If Key Refresh underway, add placeholder for "Old Key" */
+ if (phase != KEY_REFRESH_PHASE_NONE) {
+ uint8_t buf[16];
+ uint8_t i;
+
+ /* Flip Bits to differentiate */
+ for (i = 0; i < sizeof(buf); i++)
+ buf[i] = key[i] ^ 0xff;
+
+ if (!add_key(jentry, "oldKey", buf))
+ goto fail;
+ }
+
if (!jarray) {
jarray = json_object_new_array();
if (!jarray)
@@ -733,7 +736,7 @@ static bool parse_bindings(json_object *jbindings, struct mesh_db_model *mod)
if (cnt > 0xffff)
return false;
- mod->num_subs = cnt;
+ mod->num_bindings = cnt;
/* Allow empty bindings list */
if (!cnt)
@@ -761,6 +764,130 @@ static bool parse_bindings(json_object *jbindings, struct mesh_db_model *mod)
return true;
}
+static bool get_key_index(json_object *jobj, const char *keyword,
+ uint16_t *index)
+{
+ int idx;
+
+ if (!get_int(jobj, keyword, &idx))
+ return false;
+
+ if (!CHECK_KEY_IDX_RANGE(idx))
+ return false;
+
+ *index = (uint16_t) idx;
+ return true;
+}
+
+static struct mesh_db_pub *parse_model_publication(json_object *jpub)
+{
+ json_object *jvalue;
+ struct mesh_db_pub *pub;
+ int len, value;
+ char *str;
+
+ pub = l_new(struct mesh_db_pub, 1);
+ if (!pub)
+ return NULL;
+
+ json_object_object_get_ex(jpub, "address", &jvalue);
+ str = (char *)json_object_get_string(jvalue);
+ len = strlen(str);
+
+ switch (len) {
+ case 4:
+ if (sscanf(str, "%04hx", &pub->addr) != 1)
+ goto fail;
+ break;
+ case 32:
+ if (!str2hex(str, len, pub->virt_addr, 16))
+ goto fail;
+ pub->virt = true;
+ break;
+ default:
+ goto fail;
+ }
+
+ if (!get_key_index(jpub, "index", &pub->idx))
+ goto fail;
+
+ if (!get_int(jpub, "ttl", &value))
+ goto fail;
+ pub->ttl = (uint8_t) value;
+
+ if (!get_int(jpub, "period", &value))
+ goto fail;
+ pub->period = (uint8_t) value;
+
+ if (!get_int(jpub, "credentials", &value))
+ goto fail;
+ pub->credential = (uint8_t) value;
+
+ if (!get_int(jpub, "retransmit", &value))
+ goto fail;
+
+ pub->retransmit = (uint8_t) value;
+ return pub;
+
+fail:
+ l_free(pub);
+ return NULL;
+}
+
+static bool parse_model_subscriptions(json_object *jsubs,
+ struct mesh_db_model *mod)
+{
+ struct mesh_db_sub *subs;
+ int i, cnt;
+
+ if (json_object_get_type(jsubs) != json_type_array)
+ return NULL;
+
+ cnt = json_object_array_length(jsubs);
+ /* Allow empty array */
+ if (!cnt)
+ return true;
+
+ subs = l_new(struct mesh_db_sub, cnt);
+ if (!subs)
+ return false;
+
+ for (i = 0; i < cnt; ++i) {
+ char *str;
+ int len;
+ json_object *jvalue;
+
+ jvalue = json_object_array_get_idx(jsubs, i);
+ if (!jvalue)
+ return false;
+
+ str = (char *)json_object_get_string(jvalue);
+ len = strlen(str);
+
+ switch (len) {
+ case 4:
+ if (sscanf(str, "%04hx", &subs[i].src.addr) != 1)
+ goto fail;
+ break;
+ case 32:
+ if (!str2hex(str, len, subs[i].src.virt_addr, 16))
+ goto fail;
+ subs[i].virt = true;
+ break;
+ default:
+ goto fail;
+ }
+ }
+
+ mod->num_subs = cnt;
+ mod->subs = subs;
+
+ return true;
+fail:
+ l_free(subs);
+ return false;
+}
+
static bool parse_models(json_object *jmodels, struct mesh_db_element *ele)
{
int i, num_models;
@@ -810,11 +937,22 @@ static bool parse_models(json_object *jmodels, struct mesh_db_element *ele)
json_object_object_get_ex(jmodel, "bind", &jarray);
- if (jarray && (json_object_get_type(jmodels) != json_type_array
+ if (jarray && (json_object_get_type(jarray) != json_type_array
|| !parse_bindings(jarray, mod)))
goto fail;
- /* TODO add pub/sub */
+ json_object_object_get_ex(jmodel, "publish", &jvalue);
+ if (jvalue) {
+ mod->pub = parse_model_publication(jvalue);
+ if (!mod->pub)
+ goto fail;
+ }
+
+ json_object_object_get_ex(jmodel, "subscribe", &jarray);
+
+ if (jarray && !parse_model_subscriptions(jarray, mod))
+ goto fail;
+
l_queue_push_tail(ele->models, mod);
}
@@ -1012,33 +1150,6 @@ static bool parse_composition(json_object *jcomp, struct mesh_db_node *node)
return true;
}
-static uint16_t get_prov_flags(json_object *jarray, uint16_t max_value)
-{
- int i, cnt;
- uint16_t result = 0;
-
- cnt = json_object_array_length(jarray);
- if (!cnt)
- return 0;
-
- for (i = 0; i < cnt; ++i) {
- json_object *jvalue;
- int value;
-
- jvalue = json_object_array_get_idx(jarray, i);
- value = json_object_get_int(jvalue);
- if (value > 16)
- continue;
-
- if ((1 << value) > max_value)
- continue;
-
- result |= (1 << value);
- }
-
- return result;
-}
-
bool mesh_db_read_node(json_object *jnode, mesh_db_node_cb cb, void *user_data)
{
struct mesh_db_node node;
@@ -1091,117 +1202,28 @@ bool mesh_db_read_node(json_object *jnode, mesh_db_node_cb cb, void *user_data)
return cb(&node, user_data);
}
-bool mesh_db_read_unprovisioned_device(json_object *jnode, mesh_db_node_cb cb,
- void *user_data)
-{
- struct mesh_db_node node;
- json_object *jvalue;
- char *str;
-
- if (!cb) {
- l_info("Device read callback is required");
- return false;
- }
-
- memset(&node, 0, sizeof(node));
-
- if (!parse_composition(jnode, &node)) {
- l_info("Failed to parse local device composition");
- return false;
- }
-
- parse_features(jnode, &node);
-
- json_object_object_get_ex(jnode, "elements", &jvalue);
- if (jvalue && json_object_get_type(jvalue) == json_type_array) {
- if (!parse_elements(jvalue, &node))
- return false;
- }
-
- json_object_object_get_ex(jnode, "UUID", &jvalue);
- if (!jvalue)
- return false;
-
- str = (char *)json_object_get_string(jvalue);
- if (!str2hex(str, strlen(str), node.uuid, 16))
- return false;
-
- return cb(&node, user_data);
-}
-
-bool mesh_db_read_prov_info(json_object *jnode, struct mesh_db_prov *prov)
+bool mesh_db_write_uint16_hex(json_object *jobj, const char *desc,
+ uint16_t value)
{
- json_object *jprov, *jarray, *jvalue, *jobj;
- int value;
- char *str;
-
- if (!prov)
- return false;
-
- json_object_object_get_ex(jnode, "provision", &jprov);
- if (!jprov)
- return false;
-
- json_object_object_get_ex(jprov, "algorithms", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
-
- prov->algorithm = get_prov_flags(jarray, ALG_FIPS_256_ECC);
- if (!prov->algorithm) {
- l_info("At least one algorithm must be indicated");
- return false;
- }
-
- json_object_object_get_ex(jprov, "outputOOB", &jobj);
- json_object_object_get_ex(jobj, "size", &jvalue);
- value = json_object_get_int(jvalue);
- if (value > 8)
- return false;
-
- prov->output_oob.size = (uint8_t) value;
- json_object_object_get_ex(jobj, "actions", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
-
- prov->output_oob.actions = get_prov_flags(jarray, OOB_OUT_ALPHA);
-
- json_object_object_get_ex(jprov, "inputOOB", &jobj);
- json_object_object_get_ex(jobj, "size", &jvalue);
- value = json_object_get_int(jvalue);
- if (value > 8)
- return false;
-
- prov->input_oob.size = (uint8_t) value;
- json_object_object_get_ex(jobj, "actions", &jarray);
- if (!jarray || json_object_get_type(jarray) != json_type_array)
- return false;
-
- prov->input_oob.actions = get_prov_flags(jarray, OOB_IN_ALPHA);
-
- json_object_object_get_ex(jprov, "publicType", &jvalue);
- prov->pub_type = (json_object_get_boolean(jvalue)) ? 1 : 0;
-
- json_object_object_get_ex(jprov, "staticType", &jvalue);
- prov->static_type = (json_object_get_boolean(jvalue)) ? 1 : 0;
-
- json_object_object_get_ex(jprov, "privateKey", &jvalue);
- if (!jvalue)
- return false;
+ json_object *jstring;
+ char buf[5];
- str = (char *)json_object_get_string(jvalue);
- if (!str2hex(str, strlen(str), prov->priv_key, 32))
+ snprintf(buf, 5, "%4.4x", value);
+ jstring = json_object_new_string(buf);
+ if (!jstring)
return false;
+ json_object_object_add(jobj, desc, jstring);
return true;
}
-bool mesh_db_write_uint16_hex(json_object *jobj, const char *desc,
- uint16_t value)
+bool mesh_db_write_uint32_hex(json_object *jobj, const char *desc,
+ uint32_t value)
{
json_object *jstring;
- char buf[5];
+ char buf[9];
- snprintf(buf, 5, "%4.4x", value);
+ snprintf(buf, 9, "%8.8x", value);
jstring = json_object_new_string(buf);
if (!jstring)
return false;
@@ -1238,23 +1260,23 @@ bool mesh_db_write_bool(json_object *jobj, const char *keyword, bool value)
return true;
}
-bool mesh_db_write_mode(json_object *jobj, const char *keyword, int value)
+static const char *mode_to_string(int mode)
{
- json_object *jstring;
-
- switch (value) {
+ switch (mode) {
case MESH_MODE_DISABLED:
- jstring = json_object_new_string("disabled");
- break;
+ return "disabled";
case MESH_MODE_ENABLED:
- jstring = json_object_new_string("enabled");
- break;
- case MESH_MODE_UNSUPPORTED:
- jstring = json_object_new_string("unsupported");
- break;
+ return "enabled";
default:
- return false;
- };
+ return "unsupported";
+ }
+}
+
+bool mesh_db_write_mode(json_object *jobj, const char *keyword, int value)
+{
+ json_object *jstring;
+
+ jstring = json_object_new_string(mode_to_string(value));
if (!jstring)
return false;
@@ -1272,7 +1294,7 @@ bool mesh_db_write_relay_mode(json_object *jnode, uint8_t mode, uint8_t count,
json_object_object_del(jnode, "relay");
jrelay = json_object_new_object();
- if (jrelay)
+ if (!jrelay)
return false;
if (!mesh_db_write_mode(jrelay, "mode", mode))
@@ -1359,3 +1381,113 @@ void mesh_db_remove_property(json_object *jobj, const char *desc)
{
json_object_object_del(jobj, desc);
}
+
+static void add_model(void *a, void *b)
+{
+ struct mesh_db_model *mod = a;
+ json_object *jmodels = b, *jmodel;
+
+ jmodel = json_object_new_object();
+ if (!jmodel)
+ return;
+
+ if (!mod->vendor)
+ mesh_db_write_uint16_hex(jmodel, "modelId",
+ (uint16_t) mod->id);
+ else
+ mesh_db_write_uint32_hex(jmodel, "modelId", mod->id);
+
+ json_object_array_add(jmodels, jmodel);
+}
+
+/* Add unprovisioned node (local) */
+bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node) {
+
+ struct mesh_db_modes *modes = &node->modes;
+ const struct l_queue_entry *entry;
+ json_object *jelements;
+
+ /* CID, PID, VID, crpl */
+ if (!mesh_db_write_uint16_hex(jnode, "cid", node->cid))
+ return false;
+
+ if (!mesh_db_write_uint16_hex(jnode, "pid", node->pid))
+ return false;
+
+ if (!mesh_db_write_uint16_hex(jnode, "vid", node->vid))
+ return false;
+
+ if (!mesh_db_write_uint16_hex(jnode, "crpl", node->crpl))
+ return false;
+
+ /* Device UUID */
+ if (!add_key(jnode, "UUID", node->uuid))
+ return false;
+
+ /* Features: relay, LPN, friend, proxy*/
+ if (!mesh_db_write_relay_mode(jnode, modes->relay.state,
+ modes->relay.cnt,
+ modes->relay.interval))
+ return false;
+
+ if (!mesh_db_write_mode(jnode, "lowPower", modes->lpn))
+ return false;
+
+ if (!mesh_db_write_mode(jnode, "friend", modes->friend))
+ return false;
+
+ if (!mesh_db_write_mode(jnode, "proxy", modes->proxy))
+ return false;
+
+ /* Beaconing state */
+ if (!mesh_db_write_mode(jnode, "beacon", modes->beacon))
+ return false;
+
+ /* Sequence number */
+ json_object_object_add(jnode, "sequenceNumber",
+ json_object_new_int(node->seq_number));
+
+ /* Default TTL */
+ json_object_object_add(jnode, "defaultTTL",
+ json_object_new_int(node->ttl));
+
+ /* Elements */
+ jelements = json_object_new_array();
+ if (!jelements)
+ return false;
+
+ entry = l_queue_get_entries(node->elements);
+
+ for (; entry; entry = entry->next) {
+ struct mesh_db_element *ele = entry->data;
+ json_object *jelement, *jmodels;
+
+ jelement = json_object_new_object();
+
+ if (!jelement) {
+ json_object_put(jelements);
+ return false;
+ }
+
+ mesh_db_write_int(jelement, "elementIndex", ele->index);
+ mesh_db_write_uint16_hex(jelement, "location", ele->location);
+ json_object_array_add(jelements, jelement);
+
+ /* Models */
+ if (l_queue_isempty(ele->models))
+ continue;
+
+ jmodels = json_object_new_array();
+ if (!jmodels) {
+ json_object_put(jelements);
+ return false;
+ }
+
+ json_object_object_add(jelement, "models", jmodels);
+ l_queue_foreach(ele->models, add_model, jmodels);
+ }
+
+ json_object_object_add(jnode, "elements", jelements);
+
+ return true;
+}
diff --git a/mesh/mesh-db.h b/mesh/mesh-db.h
index 336302f28..9a32e6c76 100644
--- a/mesh/mesh-db.h
+++ b/mesh/mesh-db.h
@@ -103,9 +103,7 @@ typedef bool (*mesh_db_app_key_cb)(uint16_t idx, uint16_t net_idx,
typedef bool (*mesh_db_node_cb)(struct mesh_db_node *node, void *user_data);
bool mesh_db_read_node(json_object *jobj, mesh_db_node_cb cb, void *user_data);
-bool mesh_db_read_unprovisioned_device(json_object *jnode, mesh_db_node_cb cb,
- void *user_data);
-bool mesh_db_read_prov_info(json_object *jnode, struct mesh_db_prov *prov);
+bool mesh_db_add_node(json_object *jnode, struct mesh_db_node *node);
bool mesh_db_read_iv_index(json_object *jobj, uint32_t *idx, bool *update);
bool mesh_db_read_device_key(json_object *jobj, uint8_t key_buf[16]);
bool mesh_db_read_net_transmit(json_object *jobj, uint8_t *cnt,
@@ -124,6 +122,8 @@ bool mesh_db_write_app_key(json_object *jobj, uint16_t net_idx,
bool mesh_db_write_int(json_object *jobj, const char *keyword, int value);
bool mesh_db_write_uint16_hex(json_object *jobj, const char *desc,
uint16_t value);
+bool mesh_db_write_uint32_hex(json_object *jobj, const char *desc,
+ uint32_t value);
bool mesh_db_write_bool(json_object *jobj, const char *keyword, bool value);
bool mesh_db_write_relay_mode(json_object *jnode, uint8_t mode, uint8_t count,
uint16_t interval);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 20/30] mesh: restructure model services for multiple nodes
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (18 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 19/30] mesh: Restrusture DB to support " Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 21/30] mesh: DBUS interface for Provisioning Agent Brian Gix
` (9 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/model.c | 811 ++++++++++++++++++++++++++++++++++++++++++-----------------
mesh/model.h | 66 ++---
2 files changed, 612 insertions(+), 265 deletions(-)
diff --git a/mesh/model.c b/mesh/model.c
index d50817843..b184e963a 100644
--- a/mesh/model.c
+++ b/mesh/model.c
@@ -30,12 +30,15 @@
#include "mesh/mesh.h"
#include "mesh/crypto.h"
#include "mesh/node.h"
+#include "mesh/mesh-db.h"
#include "mesh/net.h"
#include "mesh/appkey.h"
-#include "mesh/model.h"
-#include "mesh/display.h"
#include "mesh/cfgmod.h"
#include "mesh/storage.h"
+#include "mesh/error.h"
+#include "mesh/dbus.h"
+#include "mesh/util.h"
+#include "mesh/model.h"
struct mesh_model {
const struct mesh_model_ops *cbs;
@@ -67,6 +70,7 @@ struct mod_forward {
uint8_t ttl;
int8_t rssi;
bool szmict;
+ bool has_dst;
bool done;
};
@@ -75,6 +79,14 @@ static struct l_queue *mesh_virtuals;
static uint32_t virt_id_next = VIRTUAL_BASE;
static struct timeval tx_start;
+static bool is_internal(uint32_t id)
+{
+ if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL)
+ return true;
+
+ return false;
+}
+
static void unref_virt(void *data)
{
struct mesh_virtual *virt = data;
@@ -94,6 +106,17 @@ static bool simple_match(const void *a, const void *b)
return a == b;
}
+static bool has_binding(struct l_queue *bindings, uint16_t idx)
+{
+ const struct l_queue_entry *l;
+
+ for (l = l_queue_get_entries(bindings); l; l = l->next) {
+ if (L_PTR_TO_UINT(l->data) == idx)
+ return true;
+ }
+ return false;
+}
+
static bool find_virt_by_id(const void *a, const void *b)
{
const struct mesh_virtual *virt = a;
@@ -110,13 +133,39 @@ static bool find_virt_by_addr(const void *a, const void *b)
return memcmp(virt->addr, addr, 16) == 0;
}
-static struct mesh_model *find_model(struct mesh_net *net, uint16_t addr,
+static bool match_model_id(const void *a, const void *b)
+{
+ const struct mesh_model *model = a;
+ uint32_t id = L_PTR_TO_UINT(b);
+
+ return (mesh_model_get_model_id(model) == id);
+}
+
+static struct mesh_model *get_model(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t id, int *status)
+{
+ struct l_queue *models;
+ struct mesh_model *model;
+
+ models = node_get_element_models(node, ele_idx, status);
+ if (!models) {
+ *status = MESH_STATUS_INVALID_ADDRESS;
+ return NULL;
+ }
+
+ model = l_queue_find(models, match_model_id, L_UINT_TO_PTR(id));
+
+ if (status)
+ *status = (model) ? MESH_STATUS_SUCCESS :
+ MESH_STATUS_INVALID_MODEL;
+
+ return model;
+}
+
+static struct mesh_model *find_model(struct mesh_node *node, uint16_t addr,
uint32_t mod_id, int *fail)
{
int ele_idx;
- struct mesh_node *node;
-
- node = mesh_net_local_node_get(net);
ele_idx = node_get_element_idx(node, addr);
@@ -126,7 +175,126 @@ static struct mesh_model *find_model(struct mesh_net *net, uint16_t addr,
return NULL;
}
- return node_get_model(node, (uint8_t) ele_idx, mod_id, fail);
+ return get_model(node, (uint8_t) ele_idx, mod_id, fail);
+}
+
+static uint32_t convert_pub_period_to_ms(uint8_t pub_period)
+{
+ int n;
+
+ n = (pub_period & 0x3f);
+
+ switch (pub_period >> 6) {
+ default:
+ return n * 100;
+ case 2:
+ n *= 10;
+ /* Fall Through */
+ case 1:
+ return n * 1000;
+ case 3:
+ return n * 10 * 60 * 1000;
+ }
+}
+
+static struct l_dbus_message *create_config_update_msg(struct mesh_node *node,
+ uint8_t ele_idx, uint32_t id,
+ struct l_dbus_message_builder **builder)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ const char *owner;
+ const char *path;
+ uint16_t model_id;
+
+ owner = node_get_owner(node);
+ path = node_get_element_path(node, ele_idx);
+ if (!path || !owner)
+ return NULL;
+
+ l_debug("Send \"UpdateModelConfiguration\"");
+ msg = l_dbus_message_new_method_call(dbus, owner, path,
+ MESH_ELEMENT_INTERFACE,
+ "UpdateModelConfiguration");
+
+ *builder = l_dbus_message_builder_new(msg);
+
+ model_id = (uint16_t) id;
+
+ l_dbus_message_builder_append_basic(*builder, 'q', &model_id);
+
+ l_dbus_message_builder_enter_array(*builder, "{sv}");
+
+ if ((id & VENDOR_ID_MASK) != VENDOR_ID_MASK) {
+ uint16_t vendor = id >> 16;
+ dbus_append_dict_entry_basic(*builder, "Vendor", "q", &vendor);
+ }
+
+ return msg;
+}
+
+static void config_update_model_pub_period(struct mesh_node *node,
+ uint8_t ele_idx, uint32_t model_id,
+ uint32_t period)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ struct l_dbus_message_builder *builder;
+
+ msg = create_config_update_msg(node, ele_idx, model_id, &builder);
+ if (!msg)
+ return;
+
+ dbus_append_dict_entry_basic(builder, "PublicationPeriod", "u",
+ &period);
+
+ l_dbus_message_builder_leave_array(builder);
+ if (l_dbus_message_builder_finalize(builder))
+ l_dbus_send(dbus, msg);
+
+ l_dbus_message_builder_destroy(builder);
+}
+
+static void append_dict_uint16_array(struct l_dbus_message_builder *builder,
+ struct l_queue *q, const char *key)
+{
+ const struct l_queue_entry *entry;
+
+ l_dbus_message_builder_enter_dict(builder, "sv");
+ l_dbus_message_builder_append_basic(builder, 's', key);
+ l_dbus_message_builder_enter_variant(builder, "aq");
+ l_dbus_message_builder_enter_array(builder, "q");
+
+ for (entry = l_queue_get_entries(q); entry; entry = entry->next) {
+ uint16_t value = (uint16_t) L_PTR_TO_UINT(entry->data);
+
+ l_dbus_message_builder_append_basic(builder,'q', &value);
+ }
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_variant(builder);
+ l_dbus_message_builder_leave_dict(builder);
+}
+
+static void config_update_model_bindings(struct mesh_node *node,
+ struct mesh_model *mod)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ struct l_dbus_message_builder *builder;
+
+ msg = create_config_update_msg(node, mod->ele_idx, mod->id,
+ &builder);
+ if (!msg)
+ return;
+
+ append_dict_uint16_array(builder, mod->bindings, "Bindings");
+
+ l_dbus_message_builder_leave_array(builder);
+ if (l_dbus_message_builder_finalize(builder))
+ l_dbus_send(dbus, msg);
+
+ l_dbus_message_builder_destroy(builder);
}
static void forward_model(void *a, void *b)
@@ -135,22 +303,22 @@ static void forward_model(void *a, void *b)
struct mod_forward *fwd = b;
struct mesh_virtual *virt;
uint32_t dst;
- bool has_dst = false;
-
- if (!mod->cbs || !mod->cbs->recv)
- return;
+ bool result;
l_debug("model %8.8x with idx %3.3x", mod->id, fwd->idx);
- if (fwd->idx != APP_IDX_DEV &&
- !l_queue_find(mod->bindings, simple_match,
- L_UINT_TO_PTR(fwd->idx)))
+ if (fwd->idx != APP_IDX_DEV && !has_binding(mod->bindings, fwd->idx))
return;
dst = fwd->dst;
if (dst == fwd->unicast || IS_ALL_NODES(dst))
- has_dst = true;
+ fwd->has_dst = true;
else if (fwd->virt) {
virt = l_queue_find(mod->virtuals, simple_match, fwd->virt);
+
+ /* Check that this is not own publication */
+ if (mod->pub && (virt && virt->id == mod->pub->addr))
+ return;
+
if (virt) {
/*
* Map Virtual addresses to a usable namespace that
@@ -158,42 +326,38 @@ static void forward_model(void *a, void *b)
* (multiple Virtual Addresses that map to the same
* u16 OTA addr)
*/
- has_dst = true;
+ fwd->has_dst = true;
dst = virt->id;
}
} else {
if (l_queue_find(mod->subs, simple_match, L_UINT_TO_PTR(dst)))
- has_dst = true;
+ fwd->has_dst = true;
}
+ if (!fwd->has_dst)
+ return;
- if (!has_dst)
+ /* Return, if this is not a internal model */
+ if (!mod->cbs)
return;
- /*
- * TODO: models shall be registered with a list of supported opcodes and
- * element address. Iterate through the list of opcodes to see if the
- * model is an addressee.
- * If this is an internal registered model, check for a "bind" callback.
- * For an external ("user") model, send D-Bus method (signal?) (TBD)
- */
+ result = false;
+
if (mod->cbs->recv)
- mod->cbs->recv(fwd->src, dst, fwd->unicast, fwd->idx,
+ result = mod->cbs->recv(fwd->src, dst, fwd->unicast, fwd->idx,
fwd->data, fwd->size, fwd->ttl, mod->user_data);
- if (dst == fwd->unicast)
+ if (dst == fwd->unicast && result)
fwd->done = true;
}
-static int dev_packet_decrypt(struct mesh_net *net, const uint8_t *data,
+static int dev_packet_decrypt(struct mesh_node *node, const uint8_t *data,
uint16_t size, bool szmict, uint16_t src,
uint16_t dst, uint8_t key_id, uint32_t seq,
uint32_t iv_idx, uint8_t *out)
{
- struct mesh_node *node;
const uint8_t *dev_key;
- node = mesh_net_local_node_get(net);
dev_key = node_get_device_key(node);
if (!dev_key)
return false;
@@ -241,32 +405,32 @@ static void cmplt(uint16_t remote, uint8_t status,
struct timeval tx_end;
if (status)
- l_info("Tx-->%4.4x (%d octets) Failed (%d)",
+ l_debug("Tx-->%4.4x (%d octets) Failed (%d)",
remote, size, status);
else
- l_info("Tx-->%4.4x (%d octets) Succeeded", remote, size);
+ l_debug("Tx-->%4.4x (%d octets) Succeeded", remote, size);
/* print_packet("Sent Data", data, size); */
gettimeofday(&tx_end, NULL);
if (tx_end.tv_sec == tx_start.tv_sec) {
- l_info("Duration 0.%zu seconds",
+ l_debug("Duration 0.%zu seconds",
tx_end.tv_usec - tx_start.tv_usec);
} else {
if (tx_start.tv_usec > tx_end.tv_usec)
- l_info("Duration %zu.%zu seconds",
+ l_debug("Duration %zu.%zu seconds",
tx_end.tv_sec - tx_start.tv_sec - 1,
tx_end.tv_usec + 1000000 - tx_start.tv_usec);
else
- l_info("Duration %zu.%zu seconds",
+ l_debug("Duration %zu.%zu seconds",
tx_end.tv_sec - tx_start.tv_sec,
tx_end.tv_usec - tx_start.tv_usec);
}
}
-static bool pub_frnd_cred(struct mesh_net *net, uint16_t src, uint32_t mod_id)
+static bool pub_frnd_cred(struct mesh_node *node, uint16_t src, uint32_t mod_id)
{
- struct mesh_model *mod = find_model(net, src, mod_id, NULL);
+ struct mesh_model *mod = find_model(node, src, mod_id, NULL);
if (!mod || !mod->pub)
return false;
@@ -274,17 +438,16 @@ static bool pub_frnd_cred(struct mesh_net *net, uint16_t src, uint32_t mod_id)
return (mod->pub->credential != 0);
}
-static unsigned int msg_send(struct mesh_net *net, uint32_t mod_id,
- uint16_t src, uint32_t dst,
- uint8_t key_id, const uint8_t *key,
- uint8_t *aad, uint8_t ttl,
- const void *msg, uint16_t msg_len)
+static bool msg_send(struct mesh_node *node, bool credential, uint16_t src,
+ uint32_t dst, uint8_t key_id, const uint8_t *key,
+ uint8_t *aad, uint8_t ttl, const void *msg, uint16_t msg_len)
{
- unsigned int ret = 0;
+ bool ret = false;
uint32_t iv_index, seq_num;
uint8_t *out;
bool szmic = false;
uint16_t out_len = msg_len + sizeof(uint32_t);
+ struct mesh_net *net = node_get_net(node);
/* Use large MIC if it doesn't affect segmentation */
if (msg_len > 11 && msg_len <= 376) {
@@ -309,7 +472,7 @@ static unsigned int msg_send(struct mesh_net *net, uint32_t mod_id,
/* print_packet("Encrypted with", key, 16); */
- ret = mesh_net_app_send(net, pub_frnd_cred(net, src, mod_id),
+ ret = mesh_net_app_send(net, credential,
src, dst, key_id, ttl,
seq_num, iv_index,
szmic,
@@ -320,79 +483,100 @@ done:
return ret;
}
-static void model_unbind_idx(void *a, void *b)
+static void remove_pub(struct mesh_node *node, struct mesh_model *mod)
{
- struct mesh_model *mod = a;
- uint16_t idx = L_PTR_TO_UINT(b);
+ l_free(mod->pub);
+ mod->pub = NULL;
- if (idx == mod->pub->idx) {
- mod->pub->addr = UNASSIGNED_ADDRESS;
- /*
- * TODO: callback for internal model or
- * D-Bus signal/method "model publication changed" (TBD)
- */
- }
+ /* TODO: remove from storage */
+
+ if (!mod->cbs)
+ /* External models */
+ config_update_model_pub_period(node, mod->ele_idx, mod->id, 0);
+ else if (mod->cbs && mod->cbs->pub)
+ /* Internal models */
+ mod->cbs->pub(NULL);
+}
- l_queue_remove(mod->bindings, b);
+static void model_unbind_idx(struct mesh_node *node, struct mesh_model *mod,
+ uint16_t idx)
+{
+ l_queue_remove(mod->bindings, L_UINT_TO_PTR(idx));
- if (mod->cbs->bind)
+ if (!mod->cbs)
+ /* External model */
+ config_update_model_bindings(node, mod);
+ else if (mod->cbs->bind)
+ /* Internal model */
mod->cbs->bind(idx, ACTION_DELETE);
+
+ if (mod->pub && idx != mod->pub->idx)
+ return;
+
+ /* Remove model publication if the publication key is unbound */
+ remove_pub(node, mod);
}
-static int model_bind_idx(struct mesh_model *mod, uint16_t idx)
+static void model_bind_idx(struct mesh_node *node, struct mesh_model *mod,
+ uint16_t idx)
{
- if (l_queue_length(mod->bindings) >= MAX_BINDINGS)
- return MESH_STATUS_INSUFF_RESOURCES;
+ l_queue_push_tail(mod->bindings, L_UINT_TO_PTR(idx));
- if (!l_queue_push_tail(mod->bindings, L_UINT_TO_PTR(idx)))
- return MESH_STATUS_INSUFF_RESOURCES;
+ l_debug("Add %4.4x to model %8.8x", idx, mod->id);
- if (mod->cbs->bind)
+ if (!mod->cbs)
+ /* External model */
+ config_update_model_bindings(node, mod);
+ else if (mod->cbs->bind)
+ /* Internal model */
mod->cbs->bind(idx, ACTION_ADD);
-
- return MESH_STATUS_SUCCESS;
-
}
-static int update_binding(struct mesh_net *net, uint16_t addr, uint32_t id,
+static int update_binding(struct mesh_node *node, uint16_t addr, uint32_t id,
uint16_t app_idx, bool unbind)
{
int fail;
struct mesh_model *mod;
- int status;
+ bool is_present;
- mod = find_model(net, addr, id, &fail);
+ mod = find_model(node, addr, id, &fail);
if (!mod) {
- l_info("model not found");
+ l_debug("Model not found");
return fail;
}
+ id = (id >= VENDOR_ID_MASK) ? (id & 0xffff) : id;
+
if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL)
return MESH_STATUS_INVALID_MODEL;
- if (!l_queue_find(mod->bindings, simple_match, L_UINT_TO_PTR(app_idx)))
- return MESH_STATUS_CANNOT_BIND;
-
- if (!appkey_have_key(net, app_idx))
+ if (!appkey_have_key(node_get_net(node), app_idx))
return MESH_STATUS_INVALID_APPKEY;
+ is_present = has_binding(mod->bindings, app_idx);
+
+ if (!is_present && unbind)
+ return MESH_STATUS_SUCCESS;
+
+ if (is_present && !unbind)
+ return MESH_STATUS_SUCCESS;
+
if (unbind) {
- model_unbind_idx(mod, &app_idx);
+ model_unbind_idx(node, mod, app_idx);
- if (!storage_model_bind(net, addr, id, app_idx, true))
+ if (!storage_model_bind(node, addr, id, app_idx, true))
return MESH_STATUS_STORAGE_FAIL;
return MESH_STATUS_SUCCESS;
}
- status = model_bind_idx(mod, app_idx);
- if (status != MESH_STATUS_SUCCESS)
- return status;
+ if (l_queue_length(mod->bindings) >= MAX_BINDINGS)
+ return MESH_STATUS_INSUFF_RESOURCES;
- if (!storage_model_bind(net, addr, id, app_idx, false)) {
- model_unbind_idx(mod, &app_idx);
+ if (!storage_model_bind(node, addr, id, app_idx, false))
return MESH_STATUS_STORAGE_FAIL;
- }
+
+ model_bind_idx(node, mod, app_idx);
return MESH_STATUS_SUCCESS;
@@ -428,6 +612,7 @@ static int set_pub(struct mesh_model *mod, const uint8_t *mod_addr,
}
}
+ mod->pub = l_new(struct mesh_model_pub, 1);
if (b_virt) {
virt = l_queue_find(mesh_virtuals, find_virt_by_addr, mod_addr);
if (!virt) {
@@ -511,14 +696,57 @@ static int add_sub(struct mesh_net *net, struct mesh_model *mod,
l_queue_push_tail(mod->subs, L_UINT_TO_PTR(grp));
- l_info("Added %4.4x", grp);
- if (net)
- mesh_net_dst_reg(net, grp);
+ l_debug("Added %4.4x", grp);
+
+ mesh_net_dst_reg(net, grp);
return MESH_STATUS_SUCCESS;
}
-bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
+static void send_msg_rcvd(struct mesh_node *node, uint8_t ele_idx, bool is_sub,
+ uint16_t src, uint16_t key_idx,
+ uint16_t size, const uint8_t *data)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ struct l_dbus_message_builder *builder;
+ const char *owner;
+ const char *path;
+
+ owner = node_get_owner(node);
+ path = node_get_element_path(node, ele_idx);
+ if (!path || !owner)
+ return;
+
+ l_debug("Send \"MessageReceived\"");
+
+ msg = l_dbus_message_new_method_call(dbus, owner, path,
+ MESH_ELEMENT_INTERFACE, "MessageReceived");
+
+ builder = l_dbus_message_builder_new(msg);
+
+ if (!l_dbus_message_builder_append_basic(builder, 'q', &src))
+ goto error;
+
+ if (!l_dbus_message_builder_append_basic(builder, 'q', &key_idx))
+ goto error;
+
+ if (!l_dbus_message_builder_append_basic(builder, 'b', &is_sub))
+ goto error;
+
+ if (!dbus_append_byte_array(builder, data, size))
+ goto error;
+
+ if (!l_dbus_message_builder_finalize(builder))
+ goto error;
+
+ l_dbus_send(dbus, msg);
+
+error:
+ l_dbus_message_builder_destroy(builder);
+}
+
+bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
uint32_t seq, uint32_t iv_index, uint8_t ttl,
uint16_t src, uint16_t dst, uint8_t key_id,
const uint8_t *data, uint16_t size)
@@ -531,30 +759,25 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
.size = size - (szmict ? 8 : 4),
.ttl = ttl,
.virt = NULL,
- .done = false,
};
-
- struct mesh_node *node;
+ struct mesh_net *net = node_get_net(node);
uint8_t num_ele;
int decrypt_idx, i, ele_idx;
uint16_t addr;
struct mesh_virtual *decrypt_virt = NULL;
+ bool result = false;
+ bool is_subscription;
l_debug("iv_index %8.8x key_id = %2.2x", iv_index, key_id);
if (!dst)
return false;
- node = mesh_net_local_node_get(net);
- if (!node)
- return false;
-
ele_idx = node_get_element_idx(node, dst);
if (dst < 0x8000 && ele_idx < 0)
/* Unicast and not addressed to us */
return false;
-
clear_text = l_malloc(size);
if (!clear_text)
return false;
@@ -566,7 +789,7 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
* is hinted by key_id, but is not necessarily definitive
*/
if (key_id == APP_ID_DEV || mesh_net_provisioner_mode_get(net))
- decrypt_idx = dev_packet_decrypt(net, data, size, szmict, src,
+ decrypt_idx = dev_packet_decrypt(node, data, size, szmict, src,
dst, key_id, seq0, iv_index,
clear_text);
else if ((dst & 0xc000) == 0x8000)
@@ -582,18 +805,18 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
if (decrypt_idx < 0) {
l_error("model.c - Failed to decrypt application payload");
- forward.done = false;
+ result = false;
goto done;
}
/* print_packet("Clr Rx (pre-cache-check)", clear_text, size - 4); */
if (key_id != APP_ID_DEV) {
- uint16_t crpl = mesh_net_get_crpl(net);
+ uint16_t crpl = node_get_crpl(node);
if (appkey_msg_in_replay_cache(net, (uint16_t) decrypt_idx, src,
crpl, seq, iv_index)) {
- forward.done = true;
+ result = true;
goto done;
}
}
@@ -608,59 +831,86 @@ bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
if (!num_ele || IS_UNASSIGNED(addr))
goto done;
+ is_subscription = !(IS_UNICAST(dst));
+
for (i = 0; i < num_ele; i++) {
struct l_queue *models;
- if (dst < 0x8000 && ele_idx != i)
+ if (!is_subscription && ele_idx != i)
continue;
forward.unicast = addr + i;
+ forward.has_dst = false;
+
models = node_get_element_models(node, i, NULL);
+
+ /* Internal models */
l_queue_foreach(models, forward_model, &forward);
- if (dst < 0x8000 && ele_idx == i)
+ /*
+ * Cycle through external models if the message has not been
+ * handled by internal models
+ */
+ if (forward.has_dst && !forward.done)
+ send_msg_rcvd(node, i, is_subscription, src,
+ forward.idx, forward.size,
+ forward.data);
+
+ /*
+ * Either the message has been processed internally or
+ * has been passed on to an external model.
+ */
+ result = forward.has_dst | forward.done;
+
+ /* If the message was to unicast address, we are done */
+ if (!is_subscription && ele_idx == i)
break;
}
+
done:
l_free(clear_text);
- return forward.done;
+ return result;
}
-unsigned int mesh_model_send(struct mesh_net *net, uint32_t mod_id,
- uint16_t src, uint32_t target,
- uint16_t app_idx, uint8_t ttl,
+int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
+ uint16_t src, uint8_t ttl,
const void *msg, uint16_t msg_len)
{
+ struct mesh_net *net = node_get_net(node);
struct mesh_model *mod;
+ uint32_t target;
uint8_t *aad = NULL;
uint16_t dst;
uint8_t key_id;
const uint8_t *key;
+ bool result;
/* print_packet("Mod Tx", msg, msg_len); */
if (!net || msg_len > 380)
- return 0;
+ return MESH_ERROR_INVALID_ARGS;
/* If SRC is 0, use the Primary Element */
if (src == 0)
src = mesh_net_get_address(net);
- mod = find_model(net, src, mod_id, NULL);
+ mod = find_model(node, src, mod_id, NULL);
if (!mod) {
- l_info("model %x not found", mod_id);
- return 0;
+ l_debug("model %x not found", mod_id);
+ return MESH_ERROR_NOT_FOUND;
+ }
+
+ if (!mod->pub) {
+ l_debug("publication doesn't exist (model %x)", mod_id);
+ return MESH_ERROR_DOES_NOT_EXIST;
}
gettimeofday(&tx_start, NULL);
- if (target == USE_PUB_VALUE) {
- target = mod->pub->addr;
- app_idx = mod->pub->idx;
- }
+ target = mod->pub->addr;
if (IS_UNASSIGNED(target))
- return 0;
+ return false;
if (target >= VIRTUAL_BASE) {
struct mesh_virtual *virt = l_queue_find(mesh_virtuals,
@@ -668,101 +918,139 @@ unsigned int mesh_model_send(struct mesh_net *net, uint32_t mod_id,
L_UINT_TO_PTR(target));
if (!virt)
- return 0;
+ return false;
aad = virt->addr;
dst = virt->ota;
- } else
+ } else {
dst = target;
+ }
+
+ l_debug("publish dst=%x", dst);
- l_debug("dst=%x", dst);
- if (app_idx == APP_IDX_DEV && mesh_net_provisioner_mode_get(net)) {
- key = node_get_device_key(mesh_net_local_node_get(net));
- } else if (app_idx == APP_IDX_DEV) {
- key = node_get_device_key(mesh_net_local_node_get(net));
+ key = appkey_get_key(net, mod->pub->idx, &key_id);
+ if (!key) {
+ l_debug("no app key for (%x)", mod->pub->idx);
+ return false;
+ }
+
+ l_debug("(%x) %p", mod->pub->idx, key);
+ l_debug("key_id %x", key_id);
+
+ result = msg_send(node, pub_frnd_cred(node, src, mod_id), src,
+ dst, key_id, key, aad, ttl, msg, msg_len);
+
+ return result ? MESH_ERROR_NONE : MESH_ERROR_FAILED;
+
+}
+
+bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t target,
+ uint16_t app_idx, uint8_t ttl,
+ const void *msg, uint16_t msg_len)
+{
+ uint8_t key_id;
+ const uint8_t *key;
+
+ /* print_packet("Mod Tx", msg, msg_len); */
+
+ /* If SRC is 0, use the Primary Element */
+ if (src == 0)
+ src = node_get_primary(node);
+
+ gettimeofday(&tx_start, NULL);
+
+ if (IS_UNASSIGNED(target))
+ return false;
+
+ if (app_idx == APP_IDX_DEV) {
+ key = node_get_device_key(node);
if (!key)
- return 0;
+ return false;
l_debug("(%x)", app_idx);
key_id = APP_ID_DEV;
} else {
- key = appkey_get_key(net, app_idx, &key_id);
+ key = appkey_get_key(node_get_net(node), app_idx, &key_id);
if (!key) {
l_debug("no app key for (%x)", app_idx);
- return 0;
+ return false;
}
l_debug("(%x) %p", app_idx, key);
l_debug("key_id %x", key_id);
}
- return msg_send(net, mod_id, src, dst, key_id, key, aad, ttl,
+ return msg_send(node, false, src, target, key_id, key, NULL, ttl,
msg, msg_len);
-
}
-int mesh_model_pub_set(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
const uint8_t *mod_addr, uint16_t idx, bool cred_flag,
uint8_t ttl, uint8_t period, uint8_t retransmit,
bool b_virt, uint16_t *dst)
{
int fail = MESH_STATUS_SUCCESS;
- int ele_idx = -1;
+ int ele_idx;
struct mesh_model *mod;
- struct mesh_node *node;
+ int result;
- node = mesh_net_local_node_get(net);
- if (node)
- ele_idx = node_get_element_idx(node, addr);
+ ele_idx = node_get_element_idx(node, addr);
- if (!node || ele_idx < 0) {
+ if (ele_idx < 0) {
fail = MESH_STATUS_INVALID_ADDRESS;
return false;
}
- mod = node_get_model(node, (uint8_t) ele_idx, id, &fail);
+ mod = get_model(node, (uint8_t) ele_idx, id, &fail);
if (!mod)
return fail;
if (id == CONFIG_SRV_MODEL || id == CONFIG_CLI_MODEL)
return MESH_STATUS_INVALID_PUB_PARAM;
- if (!appkey_have_key(net, idx))
+ if (!appkey_have_key(node_get_net(node), idx))
return MESH_STATUS_INVALID_APPKEY;
- return set_pub(mod, mod_addr, idx, cred_flag, ttl, period, retransmit,
+ result = set_pub(mod, mod_addr, idx, cred_flag, ttl, period, retransmit,
b_virt, dst);
+
+ if (result != MESH_STATUS_SUCCESS)
+ return result;
+
+ /* TODO: save to storage */
+
/*
- * TODO: Add standardized Publication Change notification to model
- * definition
+ * If the publication address is set to unassigned address value,
+ * remove publication
*/
+ if (IS_UNASSIGNED(*dst))
+ remove_pub(node, mod);
+
+ /* Internal model, call registered callbacks */
+ if (mod->cbs && mod->cbs->pub) {
+ mod->cbs->pub(mod->pub);
+ return MESH_STATUS_SUCCESS;
+ }
+
+ /* External model */
+ config_update_model_pub_period(node, ele_idx, id,
+ convert_pub_period_to_ms(period));
+
+ return MESH_STATUS_SUCCESS;
}
-struct mesh_model_pub *mesh_model_pub_get(struct mesh_net *net, uint8_t ele_idx,
- uint32_t mod_id, int *status)
+struct mesh_model_pub *mesh_model_pub_get(struct mesh_node *node,
+ uint8_t ele_idx, uint32_t mod_id, int *status)
{
struct mesh_model *mod;
- struct mesh_node *node = mesh_net_local_node_get(net);
-
- if (!node) {
- *status = MESH_STATUS_INVALID_ADDRESS;
- return NULL;
- }
- mod = node_get_model(node, ele_idx, mod_id, status);
+ mod = get_model(node, ele_idx, mod_id, status);
if (!mod)
return NULL;
return mod->pub;
}
-uint32_t mesh_model_get_model_id(const struct mesh_model *model)
-{
- if (!model)
- return 0xffffffff; /* TODO: use define */
- return model->id;
-}
-
void mesh_model_free(void *data)
{
struct mesh_model *mod = data;
@@ -774,33 +1062,39 @@ void mesh_model_free(void *data)
l_free(mod);
}
-struct mesh_model *mesh_model_new(uint8_t ele_idx, uint32_t id, bool vendor)
+static struct mesh_model *model_new(uint8_t ele_idx, uint32_t id)
{
struct mesh_model *mod = l_new(struct mesh_model, 1);
- if (!mod)
- return NULL;
-
- if (vendor)
- id |= VENDOR_ID_MASK;
-
mod->id = id;
mod->ele_idx = ele_idx;
mod->virtuals = l_queue_new();
- if (!mod->virtuals) {
- l_free(mod);
- return NULL;
- }
return mod;
}
-static void restore_model_state(void *data)
+struct mesh_model *mesh_model_new(uint8_t ele_idx, uint16_t id)
{
- struct mesh_model *mod = data;
+ return model_new(ele_idx, id | VENDOR_ID_MASK);
+}
+
+struct mesh_model *mesh_model_vendor_new(uint8_t ele_idx, uint16_t vendor_id,
+ uint16_t mod_id)
+{
+ uint32_t id = mod_id | (vendor_id << 16);
+
+ return model_new(ele_idx, id);
+}
+
+/* Internal models only */
+static void restore_model_state(struct mesh_model *mod)
+{
+
const struct mesh_model_ops *cbs;
const struct l_queue_entry *b;
cbs = mod->cbs;
+ if (!cbs)
+ return;
if (l_queue_isempty(mod->bindings) || !mod->cbs->bind) {
for (b = l_queue_get_entries(mod->bindings); b; b = b->next) {
@@ -812,63 +1106,64 @@ static void restore_model_state(void *data)
if (mod->pub && cbs->pub)
cbs->pub(mod->pub);
+
}
-bool mesh_model_vendor_register(struct mesh_net *net, uint8_t ele_idx,
+uint32_t mesh_model_get_model_id(const struct mesh_model *model)
+{
+ return model->id;
+}
+
+/* This registers an internal model, i.e. implemented within meshd */
+bool mesh_model_register(struct mesh_node *node, uint8_t ele_idx,
uint32_t mod_id,
const struct mesh_model_ops *cbs,
void *user_data)
{
struct mesh_model *mod;
- struct mesh_node *node;
- node = mesh_net_local_node_get(net);
- if (!node)
- return false;
+ /* Internal models are always SIG models */
+ mod_id = VENDOR_ID_MASK | mod_id;
- mod = node_get_model(node, ele_idx, mod_id, NULL);
+ mod = get_model(node, ele_idx, mod_id, NULL);
if (!mod)
return false;
mod->cbs = cbs;
mod->user_data = user_data;
- l_idle_oneshot(restore_model_state, mod, NULL);
+ restore_model_state(mod);
return true;
}
-bool mesh_model_register(struct mesh_net *net, uint8_t ele_idx,
- uint32_t mod_id,
- const struct mesh_model_ops *cbs,
- void *user_data)
+void mesh_model_app_key_delete(struct mesh_node *node, struct l_queue *models,
+ uint16_t app_idx)
{
- uint32_t id = VENDOR_ID_MASK | mod_id;
+ const struct l_queue_entry *entry = l_queue_get_entries(models);
- return mesh_model_vendor_register(net, ele_idx, id, cbs, user_data);
-}
+ for (; entry; entry = entry->next) {
+ struct mesh_model *model = entry->data;;
-void mesh_model_app_key_delete(struct mesh_net *net, struct l_queue *models,
- uint16_t app_idx)
-{
- l_queue_foreach(models, model_unbind_idx, L_UINT_TO_PTR(app_idx));
+ model_unbind_idx(node, model, app_idx);
+ }
}
-int mesh_model_binding_del(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_binding_del(struct mesh_node *node, uint16_t addr, uint32_t id,
uint16_t app_idx)
{
l_debug("0x%x, 0x%x, %d", addr, id, app_idx);
- return update_binding(net, addr, id, app_idx, true);
+ return update_binding(node, addr, id, app_idx, true);
}
-int mesh_model_binding_add(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_binding_add(struct mesh_node *node, uint16_t addr, uint32_t id,
uint16_t app_idx)
{
l_debug("0x%x, 0x%x, %d", addr, id, app_idx);
- return update_binding(net, addr, id, app_idx, false);
+ return update_binding(node, addr, id, app_idx, false);
}
-int mesh_model_get_bindings(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_get_bindings(struct mesh_node *node, uint16_t addr, uint32_t id,
uint8_t *buf, uint16_t buf_size, uint16_t *size)
{
int fail;
@@ -878,7 +1173,7 @@ int mesh_model_get_bindings(struct mesh_net *net, uint16_t addr, uint32_t id,
uint32_t idx_pair;
int i;
- mod = find_model(net, addr, id, &fail);
+ mod = find_model(node, addr, id, &fail);
if (!mod) {
*size = 0;
@@ -922,7 +1217,7 @@ done:
return MESH_STATUS_SUCCESS;
}
-int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id,
uint8_t *buf, uint16_t buf_size, uint16_t *size)
{
int fail = MESH_STATUS_SUCCESS;
@@ -930,7 +1225,7 @@ int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,
struct mesh_model *mod;
const struct l_queue_entry *entry;
- mod = find_model(net, addr, id, &fail);
+ mod = find_model(node, addr, id, &fail);
if (!mod)
return fail;
@@ -951,32 +1246,29 @@ int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,
return MESH_STATUS_SUCCESS;
}
-int mesh_model_sub_add(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_add(struct mesh_node *node, uint16_t addr, uint32_t id,
const uint8_t *group, bool b_virt, uint16_t *dst)
{
int fail = MESH_STATUS_SUCCESS;
int ele_idx = -1;
struct mesh_model *mod;
- struct mesh_node *node;
- node = mesh_net_local_node_get(net);
- if (node)
- ele_idx = node_get_element_idx(node, addr);
+ ele_idx = node_get_element_idx(node, addr);
if (!node || ele_idx < 0) {
fail = MESH_STATUS_INVALID_ADDRESS;
return false;
}
- mod = node_get_model(node, (uint8_t) ele_idx, id, &fail);
+ mod = get_model(node, (uint8_t) ele_idx, id, &fail);
if (!mod)
return fail;
- return add_sub(net, mod, group, b_virt, dst);
+ return add_sub(node_get_net(node), mod, group, b_virt, dst);
/* TODO: communicate to registered models that sub has changed */
}
-int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_ovr(struct mesh_node *node, uint16_t addr, uint32_t id,
const uint8_t *group, bool b_virt, uint16_t *dst)
{
int fail = MESH_STATUS_SUCCESS;
@@ -984,7 +1276,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
struct mesh_virtual *virt;
struct mesh_model *mod;
- mod = find_model(net, addr, id, &fail);
+ mod = find_model(node, addr, id, &fail);
if (!mod)
return fail;
@@ -1009,7 +1301,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
}
}
- fail = mesh_model_sub_add(net, addr, id, group, b_virt, dst);
+ fail = mesh_model_sub_add(node, addr, id, group, b_virt, dst);
if (fail) {
/* Adding new group failed, so revert to old list */
@@ -1019,6 +1311,7 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
mod->virtuals = virtuals;
} else {
const struct l_queue_entry *entry;
+ struct mesh_net *net = node_get_net(node);
entry = l_queue_get_entries(subs);
for (; entry; entry = entry->next)
@@ -1032,14 +1325,14 @@ int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
return fail;
}
-int mesh_model_sub_del(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_del(struct mesh_node *node, uint16_t addr, uint32_t id,
const uint8_t *group, bool b_virt, uint16_t *dst)
{
int fail = MESH_STATUS_SUCCESS;
uint16_t grp;
struct mesh_model *mod;
- mod = find_model(net, addr, id, &fail);
+ mod = find_model(node, addr, id, &fail);
if (!mod)
return fail;
@@ -1062,18 +1355,19 @@ int mesh_model_sub_del(struct mesh_net *net, uint16_t addr, uint32_t id,
*dst = grp;
if (l_queue_remove(mod->subs, L_UINT_TO_PTR(grp)))
- mesh_net_dst_unreg(net, grp);
+ mesh_net_dst_unreg(node_get_net(node), grp);
return MESH_STATUS_SUCCESS;
}
-int mesh_model_sub_del_all(struct mesh_net *net, uint16_t addr, uint32_t id)
+int mesh_model_sub_del_all(struct mesh_node *node, uint16_t addr, uint32_t id)
{
int fail = MESH_STATUS_SUCCESS;
struct mesh_model *mod;
const struct l_queue_entry *entry;
+ struct mesh_net *net = node_get_net(node);
- mod = find_model(net, addr, id, &fail);
+ mod = find_model(node, addr, id, &fail);
if (!mod)
return fail;
@@ -1088,15 +1382,22 @@ int mesh_model_sub_del_all(struct mesh_net *net, uint16_t addr, uint32_t id)
return fail;
}
-struct mesh_model *mesh_model_init(struct mesh_net *net, uint8_t ele_idx,
- struct mesh_db_model *db_mod)
+struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
+ void *data)
{
+ struct mesh_db_model *db_mod = data;
struct mesh_model *mod;
+ struct mesh_net *net;
uint32_t i;
- mod = mesh_model_new(ele_idx, db_mod->id, db_mod->vendor);
- if (!mod)
+ if (db_mod->num_bindings > MAX_BINDINGS) {
+ l_warn("Binding list too long %u (max %u)",
+ db_mod->num_bindings, MAX_BINDINGS);
return NULL;
+ }
+
+ mod = model_new(ele_idx, db_mod->vendor ? db_mod->id :
+ db_mod->id | VENDOR_ID_MASK);
/* Implicitly bind config server model to device key */
if (db_mod->id == CONFIG_SRV_MODEL) {
@@ -1113,35 +1414,27 @@ struct mesh_model *mesh_model_init(struct mesh_net *net, uint8_t ele_idx,
return mod;
}
+ net = node_get_net(node);
+
/* Add application key bindings if present */
if (db_mod->bindings) {
mod->bindings = l_queue_new();
-
- if (!mod->bindings) {
- mesh_model_free(mod);
- return NULL;
- }
-
- for (i = 0; i < db_mod->num_bindings; i++) {
- if (!model_bind_idx(mod, db_mod->bindings[i])) {
- mesh_model_free(mod);
- return NULL;
- }
- }
+ for (i = 0; i < db_mod->num_bindings; i++)
+ model_bind_idx(node, mod, db_mod->bindings[i]);
}
/* Add publication if present */
if (db_mod->pub) {
- uint16_t mod_addr;
- uint8_t *dst;
+ struct mesh_db_pub *pub = db_mod->pub;
+ uint8_t mod_addr[2];
+ uint8_t *pub_addr;
- l_put_le16(db_mod->pub->addr, &mod_addr);
- dst = db_mod->pub->virt ? db_mod->pub->virt_addr :
- (uint8_t *) &mod_addr;
+ /* Add publication */
+ l_put_le16(pub->addr, &mod_addr);
+ pub_addr = pub->virt ? pub->virt_addr : (uint8_t *) &mod_addr;
- if (set_pub(mod, dst, db_mod->pub->idx, db_mod->pub->credential,
- db_mod->pub->ttl, db_mod->pub->period,
- db_mod->pub->retransmit, db_mod->pub->virt, NULL) !=
+ if (set_pub(mod, pub_addr, pub->idx, pub->credential, pub->ttl,
+ pub->period, pub->retransmit, pub->virt, NULL) !=
MESH_STATUS_SUCCESS) {
mesh_model_free(mod);
return NULL;
@@ -1192,7 +1485,7 @@ uint16_t mesh_model_opcode_set(uint32_t opcode, uint8_t *buf)
return 3;
}
- l_info("Illegal Opcode %x", opcode);
+ l_debug("Illegal Opcode %x", opcode);
return 0;
}
@@ -1238,7 +1531,7 @@ bool mesh_model_opcode_get(const uint8_t *buf, uint16_t size,
return true;
}
-void mesh_model_add_virtual(struct mesh_net *net, const uint8_t *v)
+void mesh_model_add_virtual(struct mesh_node *node, const uint8_t *v)
{
struct mesh_virtual *virt = l_queue_find(mesh_virtuals,
find_virt_by_addr, v);
@@ -1263,7 +1556,7 @@ void mesh_model_add_virtual(struct mesh_net *net, const uint8_t *v)
l_queue_push_head(mesh_virtuals, virt);
}
-void mesh_model_del_virtual(struct mesh_net *net, uint32_t va24)
+void mesh_model_del_virtual(struct mesh_node *node, uint32_t va24)
{
struct mesh_virtual *virt = l_queue_remove_if(mesh_virtuals,
find_virt_by_id,
@@ -1272,3 +1565,55 @@ void mesh_model_del_virtual(struct mesh_net *net, uint32_t va24)
if (virt)
unref_virt(virt);
}
+
+void model_build_config(void *model, void *msg_builder)
+{
+ struct l_dbus_message_builder *builder = msg_builder;
+ struct mesh_model *mod = model;
+ uint16_t id;
+
+ if (is_internal(mod->id))
+ return;
+
+ if (!l_queue_length(mod->subs) && !l_queue_length(mod->virtuals) &&
+ !mod->pub && !l_queue_length(mod->bindings))
+ return;
+
+ l_dbus_message_builder_enter_struct(builder, "qa{sv}");
+
+ /* Model id */
+ id = mod->id & 0xffff;
+ l_dbus_message_builder_append_basic(builder, 'q', &id);
+
+ l_dbus_message_builder_enter_array(builder, "{sv}");
+
+ /* For vendor models, add vendor id */
+ if ((mod->id & VENDOR_ID_MASK) != VENDOR_ID_MASK) {
+ uint16_t vendor = mod->id >> 16;
+ dbus_append_dict_entry_basic(builder, "Vendor", "q", &vendor);
+ }
+
+ /* Model bindings, if present */
+ if (l_queue_length(mod->bindings))
+ append_dict_uint16_array(builder, mod->bindings, "Bindings");
+
+ /* Model periodic publication interval, if present */
+ if (mod->pub) {
+ uint32_t period = convert_pub_period_to_ms(mod->pub->period);
+ dbus_append_dict_entry_basic(builder, "PublicationPeriod", "u",
+ &period);
+ }
+
+ l_dbus_message_builder_leave_array(builder);
+ l_dbus_message_builder_leave_struct(builder);
+}
+
+void mesh_model_init(void)
+{
+ mesh_virtuals = l_queue_new();
+}
+
+void mesh_model_cleanup(void)
+{
+ l_queue_destroy(mesh_virtuals, l_free);
+}
diff --git a/mesh/model.h b/mesh/model.h
index 3a41bd722..95acfe588 100644
--- a/mesh/model.h
+++ b/mesh/model.h
@@ -85,62 +85,64 @@ struct mesh_model_ops {
mesh_model_sub_cb sub;
};
-struct mesh_model *mesh_model_new(uint8_t ele_idx, uint32_t id, bool vendor);
+struct mesh_model *mesh_model_new(uint8_t ele_idx, uint16_t mod_id);
+struct mesh_model *mesh_model_vendor_new(uint8_t ele_idx, uint16_t vendor_id,
+ uint16_t mod_id);
void mesh_model_free(void *data);
uint32_t mesh_model_get_model_id(const struct mesh_model *model);
-bool mesh_model_vendor_register(struct mesh_net *net, uint8_t ele_idx,
- uint32_t mod_id,
- const struct mesh_model_ops *cbs,
- void *user_data);
-bool mesh_model_register(struct mesh_net *net, uint8_t ele_idx, uint32_t mod_id,
- const struct mesh_model_ops *cbs,
+bool mesh_model_register(struct mesh_node *node, uint8_t ele_idx,
+ uint32_t mod_id, const struct mesh_model_ops *cbs,
void *user_data);
-struct mesh_model_pub *mesh_model_pub_get(struct mesh_net *net, uint8_t ele_idx,
- uint32_t mod_id, int *status);
-int mesh_model_pub_set(struct mesh_net *net, uint16_t addr, uint32_t id,
+struct mesh_model_pub *mesh_model_pub_get(struct mesh_node *node,
+ uint8_t ele_idx, uint32_t mod_id, int *status);
+int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id,
const uint8_t *mod_addr, uint16_t idx, bool cred_flag,
uint8_t ttl, uint8_t period, uint8_t retransmit,
bool b_virt, uint16_t *dst);
-struct mesh_model *mesh_model_init(struct mesh_net *net, uint8_t ele_idx,
- struct mesh_db_model *db_mod);
+struct mesh_model *mesh_model_setup(struct mesh_node *node, uint8_t ele_idx,
+ void *data);
-int mesh_model_binding_add(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_binding_add(struct mesh_node *node, uint16_t addr, uint32_t id,
uint16_t app_idx);
-int mesh_model_binding_del(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_binding_del(struct mesh_node *node, uint16_t addr, uint32_t id,
uint16_t idx);
-int mesh_model_get_bindings(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_get_bindings(struct mesh_node *node, uint16_t addr, uint32_t id,
uint8_t *buf, uint16_t buf_len, uint16_t *size);
-int mesh_model_sub_add(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_add(struct mesh_node *node, uint16_t addr, uint32_t id,
const uint8_t *grp, bool b_virt,
uint16_t *dst);
-int mesh_model_sub_del(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_del(struct mesh_node *node, uint16_t addr, uint32_t id,
const uint8_t *grp, bool b_virt,
uint16_t *dst);
-int mesh_model_sub_del_all(struct mesh_net *net, uint16_t addr, uint32_t id);
-int mesh_model_sub_ovr(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_del_all(struct mesh_node *node, uint16_t addr, uint32_t id);
+int mesh_model_sub_ovr(struct mesh_node *node, uint16_t addr, uint32_t id,
const uint8_t *grp, bool b_virt,
uint16_t *dst);
-int mesh_model_sub_get(struct mesh_net *net, uint16_t addr, uint32_t id,
+int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id,
uint8_t *buf, uint16_t buf_size, uint16_t *size);
uint16_t mesh_model_cfg_blk(uint8_t *pkt);
-unsigned int mesh_model_send(struct mesh_net *net, uint32_t mod_id,
- uint16_t src, uint32_t target,
- uint16_t app_idx, uint8_t ttl,
+bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t target,
+ uint16_t app_idx, uint8_t ttl,
+ const void *msg, uint16_t msg_len);
+int mesh_model_publish(struct mesh_node *node, uint32_t mod_id,
+ uint16_t src, uint8_t ttl,
const void *msg, uint16_t msg_len);
-
-bool mesh_model_rx(struct mesh_net *net, bool szmict, uint32_t seq0,
+bool mesh_model_rx(struct mesh_node *node, bool szmict, uint32_t seq0,
uint32_t seq, uint32_t iv_index, uint8_t ttl,
uint16_t src, uint16_t dst, uint8_t key_id,
const uint8_t *data, uint16_t size);
-void mesh_model_app_key_generate_new(struct mesh_net *net, uint16_t net_idx);
-void mesh_model_app_key_delete(struct mesh_net *net, struct l_queue *models,
+void mesh_model_app_key_generate_new(struct mesh_node *node, uint16_t net_idx);
+void mesh_model_app_key_delete(struct mesh_node *node, struct l_queue *models,
uint16_t idx);
-struct l_queue *mesh_model_get_appkeys(struct mesh_net *net);
-void *mesh_model_get_local_node_data(struct mesh_net *net);
-void mesh_model_add_virtual(struct mesh_net *net, const uint8_t *v);
-void mesh_model_del_virtual(struct mesh_net *net, uint32_t va24);
-void mesh_model_list_virtual(struct mesh_net *net);
+struct l_queue *mesh_model_get_appkeys(struct mesh_node *node);
+void mesh_model_add_virtual(struct mesh_node *node, const uint8_t *v);
+void mesh_model_del_virtual(struct mesh_node *node, uint32_t va24);
+void mesh_model_list_virtual(struct mesh_node *node);
uint16_t mesh_model_opcode_set(uint32_t opcode, uint8_t *buf);
bool mesh_model_opcode_get(const uint8_t *buf, uint16_t size,
uint32_t *opcode, uint16_t *n);
+void model_build_config(void *model, void *msg_builder);
+
+void mesh_model_init(void);
+void mesh_model_cleanup(void);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 21/30] mesh: DBUS interface for Provisioning Agent
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (19 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 20/30] mesh: restructure model services for " Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 22/30] mesh: restructure App Key storage Brian Gix
` (8 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/agent.c | 665 ++++++++++++++++++++++++++++++++++++++++++++++++-----------
mesh/agent.h | 71 +++++--
2 files changed, 593 insertions(+), 143 deletions(-)
diff --git a/mesh/agent.c b/mesh/agent.c
index 1da10b7bd..eeff5142d 100644
--- a/mesh/agent.c
+++ b/mesh/agent.c
@@ -22,208 +22,627 @@
#include <config.h>
#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <inttypes.h>
-
#include <ell/ell.h>
-#include "src/shared/shell.h"
-
-#include "mesh/util.h"
+#include "mesh/mesh.h"
+#include "mesh/provision.h"
+#include "mesh/error.h"
+#include "mesh/dbus.h"
#include "mesh/agent.h"
-struct input_request {
- enum oob_type type;
- uint16_t len;
- agent_input_cb cb;
+typedef enum {
+ MESH_AGENT_REQUEST_BLINK,
+ MESH_AGENT_REQUEST_BEEP,
+ MESH_AGENT_REQUEST_VIBRATE,
+ MESH_AGENT_REQUEST_OUT_NUMERIC,
+ MESH_AGENT_REQUEST_OUT_ALPHA,
+ MESH_AGENT_REQUEST_PUSH,
+ MESH_AGENT_REQUEST_TWIST,
+ MESH_AGENT_REQUEST_IN_NUMERIC,
+ MESH_AGENT_REQUEST_IN_ALPHA,
+ MESH_AGENT_REQUEST_STATIC_OOB,
+ MESH_AGENT_REQUEST_PRIVATE_KEY,
+ MESH_AGENT_REQUEST_PUBLIC_KEY
+} agent_request_type_t;
+
+struct agent_request {
+ agent_request_type_t type;
+ struct l_dbus_message *msg;
+ void *cb;
void *user_data;
};
-static struct input_request pending_request = {NONE, 0, NULL, NULL};
+struct mesh_agent {
+ char *path;
+ char *owner;
+ struct mesh_agent_prov_caps caps;
+ struct agent_request *req;
+};
+
+struct prov_action {
+ const char *action;
+ uint16_t output;
+ uint16_t input;
+ uint8_t size;
+};
+
+struct oob_info {
+ const char *oob;
+ uint16_t mask;
+};
+
+static struct prov_action cap_table[] = {
+ {"blink", 0x0001, 0x0000, 1},
+ {"beep", 0x0002, 0x0000, 1},
+ {"vibrate", 0x0004, 0x0000, 1},
+ {"out-numeric", 0x0008, 0x0000, 8},
+ {"out-alpha", 0x0010, 0x0000, 8},
+ {"push", 0x0000, 0x0001, 1},
+ {"twist", 0x0000, 0x0002, 1},
+ {"in-numeric", 0x0000, 0x0004, 8},
+ {"in-alpha", 0x0000, 0x0008, 8}
+};
-bool agent_completion(void)
+static struct oob_info oob_table[] = {
+ {"other", 0x0001},
+ {"uri", 0x0002},
+ {"machine-code-2d", 0x0004},
+ {"barcode", 0x0008},
+ {"nfc", 0x0010},
+ {"number", 0x0020},
+ {"string", 0x0040},
+ {"on-box", 0x0800},
+ {"in-box", 0x1000},
+ {"on-paper", 0x2000},
+ {"in-manual", 0x4000},
+ {"on-device", 0x8000}
+};
+
+static struct l_queue *agents;
+
+static bool simple_match(const void *a, const void *b)
+{
+ return a == b;
+}
+
+static void parse_prov_caps(struct mesh_agent_prov_caps *caps,
+ struct l_dbus_message_iter *property)
{
- if (pending_request.type == NONE)
- return false;
+ struct l_dbus_message_iter iter_caps;
+ const char *str;
+ uint32_t i;
+
+ if (!l_dbus_message_iter_get_variant(property, "as", &iter_caps))
+ return;
+
+ while (l_dbus_message_iter_next_entry(&iter_caps, &str)) {
+ for (i = 0; i < L_ARRAY_SIZE(cap_table); i++) {
+ if (strcmp(str, cap_table[i].action))
+ continue;
+
+ caps->output_action |= cap_table[i].output;
+ if (cap_table[i].output &&
+ caps->output_size < cap_table[i].size)
+ caps->output_size = cap_table[i].size;
+
+ caps->input_action |= cap_table[i].input;
+ if (cap_table[i].input &&
+ caps->input_size < cap_table[i].size)
+ caps->input_size = cap_table[i].size;
+
+ break;
+ }
+
+ if (!strcmp(str, "PublicOOB"))
+ caps->pub_type = 1;
+ else if (!strcmp(str, "StaticOOB"))
+ caps->static_type = 1;
+ }
- return true;
}
-static void reset_input_request(void)
+static void parse_oob_info(struct mesh_agent_prov_caps *caps,
+ struct l_dbus_message_iter *property)
{
- pending_request.type = NONE;
- pending_request.len = 0;
- pending_request.cb = NULL;
- pending_request.user_data = NULL;
+ struct l_dbus_message_iter iter_oob;
+ uint32_t i;
+ const char *str;
+
+ if (!l_dbus_message_iter_get_variant(property, "as", &iter_oob))
+ return;
+
+ while (l_dbus_message_iter_next_entry(&iter_oob, &str)) {
+ for (i = 0; i < L_ARRAY_SIZE(oob_table); i++) {
+ if (strcmp(str, oob_table[i].oob))
+ continue;
+ caps->oob_info |= oob_table[i].mask;
+ }
+ }
}
-static void try_again(void)
+static void agent_free(void *agent_data)
{
- static int try_count;
- enum oob_type type = pending_request.type;
+ struct mesh_agent *agent = agent_data;
+ mesh_error_t err;
+ mesh_agent_cb_t simple_cb;
+ mesh_agent_key_cb_t key_cb;
+ mesh_agent_number_cb_t number_cb;
- if (try_count == 2) {
- reset_input_request();
- try_count = 0;
+ if (!l_queue_find(agents, simple_match, agent))
return;
+
+ err = MESH_ERROR_DOES_NOT_EXIST;
+
+ if (agent->req && agent->req->cb) {
+ struct agent_request *req = agent->req;
+
+ switch (req->type) {
+ case MESH_AGENT_REQUEST_PUSH:
+ case MESH_AGENT_REQUEST_TWIST:
+ case MESH_AGENT_REQUEST_IN_NUMERIC:
+ number_cb = req->cb;
+ number_cb(req->user_data, err, 0);
+ break;
+ case MESH_AGENT_REQUEST_IN_ALPHA:
+ case MESH_AGENT_REQUEST_STATIC_OOB:
+ case MESH_AGENT_REQUEST_PRIVATE_KEY:
+ case MESH_AGENT_REQUEST_PUBLIC_KEY:
+ key_cb = req->cb;
+ key_cb(req->user_data, err, NULL, 0);
+ break;
+ case MESH_AGENT_REQUEST_BLINK:
+ case MESH_AGENT_REQUEST_BEEP:
+ case MESH_AGENT_REQUEST_VIBRATE:
+ case MESH_AGENT_REQUEST_OUT_NUMERIC:
+ case MESH_AGENT_REQUEST_OUT_ALPHA:
+ simple_cb = agent->req->cb;
+ simple_cb(req->user_data, err);
+ default:
+ break;
+ }
+
+ l_dbus_message_unref(req->msg);
+ l_free(req);
}
- pending_request.type = NONE;
- agent_input_request(type, pending_request.len, pending_request.cb,
- pending_request.user_data);
+ l_free(agent->path);
+ l_free(agent->owner);
+ }
+
+void mesh_agent_remove(struct mesh_agent *agent)
+{
+ if (!l_queue_find(agents, simple_match, agent))
+ return;
- try_count++;
+ agent_free(agent);
+ l_queue_remove(agents, agent);
}
-static void response_hexadecimal(const char *input, void *user_data)
+void mesh_agent_cleanup(void)
{
- uint8_t buf[MAX_HEXADECIMAL_OOB_LEN];
-
- if (!str2hex(input, strlen(input), buf, pending_request.len)) {
- bt_shell_printf("Incorrect input: expecting %d hex octets\n",
- pending_request.len);
- try_again();
+ if (!agents)
return;
+
+ l_queue_destroy(agents, agent_free);
+
+}
+
+void mesh_agent_init(void)
+{
+ if (!agents)
+ agents = l_queue_new();
+}
+
+struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
+ struct l_dbus_message_iter *properties)
+{
+ struct mesh_agent *agent;
+ const char *key, *uri_string;
+ struct l_dbus_message_iter variant;
+
+ agent = l_new(struct mesh_agent, 1);
+
+ while (l_dbus_message_iter_next_entry(properties, &key, &variant)) {
+ if (!strcmp(key, "Capabilities")) {
+ parse_prov_caps(&agent->caps, &variant);
+ } else if (!strcmp(key, "URI")) {
+ l_dbus_message_iter_get_variant(&variant, "s",
+ &uri_string);
+ /* TODO: compute hash */
+ } else if (!strcmp(key, "OutOfBandInfo")) {
+ parse_oob_info(&agent->caps, &variant);
+ }
}
- if (pending_request.cb)
- pending_request.cb(HEXADECIMAL, buf, pending_request.len,
- pending_request.user_data);
+ agent->owner = l_strdup(owner);
+ agent->path = l_strdup(path);
+
+ l_queue_push_tail(agents, agent);
+
+ return agent;
+}
+
+struct mesh_agent_prov_caps *mesh_agent_get_caps(struct mesh_agent *agent)
+{
+ if (!agent || !l_queue_find(agents, simple_match, agent))
+ return NULL;
+
+ return &agent->caps;
+}
+
+static struct agent_request *create_request(agent_request_type_t type,
+ void *cb, void *data)
+{
+ struct agent_request *req;
+
+ req = l_new(struct agent_request, 1);
+
+ req->type = type;
+ req->cb = cb;
+ req->user_data = data;
+
+ return req;
+}
+
+static mesh_error_t get_reply_error(struct l_dbus_message *reply)
+{
+ const char *name, *desc;
+
+ if (l_dbus_message_is_error(reply)) {
+
+ l_dbus_message_get_error(reply, &name, &desc);
+ l_error("Agent failed output action (%s), %s", name, desc);
+ return MESH_ERROR_FAILED;
+ }
+
+ return MESH_ERROR_NONE;
+}
+
+static void simple_reply(struct l_dbus_message *reply, void *user_data)
+{
+ struct mesh_agent *agent = user_data;
+ struct agent_request *req;
+ mesh_agent_cb_t cb;
+ mesh_error_t err;
+
+ if (!l_queue_find(agents, simple_match, agent) || !agent->req)
+ return;
+
+ req = agent->req;
+
+ err = get_reply_error(reply);
+
+ l_dbus_message_unref(req->msg);
- reset_input_request();
+ if (req->cb) {
+ cb = req->cb;
+ cb(req->user_data, err);
+ }
+
+ l_free(req);
+ agent->req = NULL;
}
-static void response_decimal(const char *input, void *user_data)
+static void numeric_reply(struct l_dbus_message *reply, void *user_data)
{
- uint8_t buf[DECIMAL_OOB_LEN];
+ struct mesh_agent *agent = user_data;
+ struct agent_request *req;
+ mesh_agent_number_cb_t cb;
+ uint32_t count;
+ mesh_error_t err;
- if (strlen(input) > pending_request.len) {
- bt_shell_printf("Bad input: expected no more than %d digits\n",
- pending_request.len);
- try_again();
+ if (!l_queue_find(agents, simple_match, agent) || !agent->req)
return;
+
+ req = agent->req;
+
+ err = get_reply_error(reply);
+
+ count = 0;
+
+ if (err == MESH_ERROR_NONE) {
+ if (!l_dbus_message_get_arguments(reply, "u", &count)) {
+ l_error("Failed to retrieve numeric input");
+ err = MESH_ERROR_FAILED;
+ }
}
- l_put_be32(atoi(input), buf);
+ l_dbus_message_unref(req->msg);
- if (pending_request.cb)
- pending_request.cb(DECIMAL, buf, DECIMAL_OOB_LEN,
- pending_request.user_data);
+ if (req->cb) {
+ cb = req->cb;
+ cb(req->user_data, err, count);
+ }
- reset_input_request();
+ l_free(req);
+ agent->req = NULL;
}
-static void response_ascii(const char *input, void *user_data)
+static void key_reply(struct l_dbus_message *reply, void *user_data)
{
- if (pending_request.cb)
- pending_request.cb(ASCII, (uint8_t *) input, strlen(input),
- pending_request.user_data);
+ struct mesh_agent *agent = user_data;
+ struct agent_request *req;
+ mesh_agent_key_cb_t cb;
+ struct l_dbus_message_iter iter_array;
+ uint32_t n = 0, expected_len = 0;
+ uint8_t buf[64];
+ mesh_error_t err;
+
+ if (!l_queue_find(agents, simple_match, agent) || !agent->req)
+ return;
+
+ req = agent->req;
+
+ err = get_reply_error(reply);
+
+ if (err != MESH_ERROR_NONE)
+ goto done;
+
+ if (!l_dbus_message_get_arguments(reply, "au", &iter_array)) {
+ l_error("Failed to retrieve key input");
+ err = MESH_ERROR_FAILED;
+ goto done;
+ }
+
+ if (!l_dbus_message_iter_get_fixed_array(&iter_array, buf, &n)) {
+ l_error("Failed to retrieve key input");
+ err = MESH_ERROR_FAILED;
+ goto done;
+ }
+
+ if (req->type == MESH_AGENT_REQUEST_PRIVATE_KEY)
+ expected_len = 32;
+ else if (MESH_AGENT_REQUEST_PUBLIC_KEY)
+ expected_len = 64;
+ else
+ expected_len = 16;
+
+ if (n != expected_len) {
+ l_error("Bad response length: %u (need %u)", n, expected_len);
+ err = MESH_ERROR_FAILED;
+ n = 0;
+ }
- reset_input_request();
+done:
+ l_dbus_message_unref(req->msg);
+
+ if (req->cb) {
+ cb = req->cb;
+ cb(req->user_data, err, buf, n);
+ }
+
+ l_free(req);
+ agent->req = NULL;
}
-static bool request_hexadecimal(uint16_t len)
+static mesh_error_t output_request(struct mesh_agent *agent, const char *action,
+ agent_request_type_t type, uint32_t cnt,
+ void *cb, void *user_data)
{
- if (len > MAX_HEXADECIMAL_OOB_LEN)
- return false;
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ struct l_dbus_message_builder *builder;
+
+ if (!l_queue_find(agents, simple_match, agent))
+ return MESH_ERROR_DOES_NOT_EXIST;
+
+ if (agent->req)
+ return MESH_ERROR_BUSY;
- bt_shell_printf("Request hexadecimal key (hex %d octets)\n", len);
- bt_shell_prompt_input("mesh", "Enter key (hex number):",
- response_hexadecimal, NULL);
+ agent->req = create_request(type, cb, user_data);
+ msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
+ MESH_PROVISION_AGENT_INTERFACE,
+ "DisplayNumeric");
+
+ builder = l_dbus_message_builder_new(msg);
+ l_dbus_message_builder_append_basic(builder, 's', action);
+ l_dbus_message_builder_append_basic(builder, 'u', &cnt);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+ l_debug("Send DisplayNumeric request to %s %s",
+ agent->owner, agent->path);
+
+ l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
+ NULL);
- return true;
+ agent->req->msg = l_dbus_message_ref(msg);
+
+ return MESH_ERROR_NONE;
}
-static uint32_t power_ten(uint8_t power)
+static mesh_error_t prompt_input(struct mesh_agent *agent, const char *action,
+ agent_request_type_t type, bool numeric,
+ void *cb, void *user_data)
{
- uint32_t ret = 1;
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ struct l_dbus_message_builder *builder;
+ const char *method_name;
+ l_dbus_message_func_t reply_cb;
+
+ if (!l_queue_find(agents, simple_match, agent))
+ return MESH_ERROR_DOES_NOT_EXIST;
+
+ if (agent->req)
+ return MESH_ERROR_BUSY;
+
+ agent->req = create_request(type, cb, user_data);
+
+ method_name = numeric ? "PromptNumeric" : "PromptStatic";
+
+ msg = l_dbus_message_new_method_call(dbus, agent->owner,
+ agent->path,
+ MESH_PROVISION_AGENT_INTERFACE,
+ method_name);
+
+ builder = l_dbus_message_builder_new(msg);
+ l_dbus_message_builder_append_basic(builder, 's', action);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+ l_debug("Send \"%s\" input request to %s %s", action,
+ agent->owner, agent->path);
- while (power--)
- ret *= 10;
+ reply_cb = numeric ? numeric_reply : key_reply;
- return ret;
+ l_dbus_send_with_reply(dbus_get_bus(), msg, reply_cb, agent, NULL);
+
+ agent->req->msg = l_dbus_message_ref(msg);
+
+ return MESH_ERROR_NONE;
}
-static bool request_decimal(uint16_t len)
+static mesh_error_t request_key(struct mesh_agent *agent,
+ agent_request_type_t type,
+ void *cb, void *user_data)
{
- bt_shell_printf("Request decimal key (0 - %d)\n", power_ten(len) - 1);
- bt_shell_prompt_input("mesh", "Enter Numeric key:", response_decimal,
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ const char *method_name;
+
+ if (!l_queue_find(agents, simple_match, agent))
+ return MESH_ERROR_DOES_NOT_EXIST;
+
+ if (agent->req)
+ return MESH_ERROR_BUSY;
+
+ agent->req = create_request(type, cb, user_data);
+
+ method_name = (type == MESH_AGENT_REQUEST_PRIVATE_KEY) ?
+ "PrivateKey" : "PublicKey";
+
+ msg = l_dbus_message_new_method_call(dbus, agent->owner,
+ agent->path,
+ MESH_PROVISION_AGENT_INTERFACE,
+ method_name);
+
+ l_debug("Send key request to %s %s", agent->owner, agent->path);
+
+ l_dbus_send_with_reply(dbus_get_bus(), msg, key_reply, agent, NULL);
+
+ agent->req->msg = l_dbus_message_ref(msg);
+
+ return MESH_ERROR_NONE;
+}
+
+mesh_error_t mesh_agent_display_string(struct mesh_agent *agent,
+ const char *str, mesh_agent_cb_t cb,
+ void *user_data)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+ struct l_dbus_message_builder *builder;
+
+ if (!l_queue_find(agents, simple_match, agent))
+ return MESH_ERROR_DOES_NOT_EXIST;
+
+ if (agent->req)
+ return MESH_ERROR_BUSY;
+
+ agent->req = create_request(MESH_AGENT_REQUEST_OUT_ALPHA,
+ cb, user_data);
+ msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
+ MESH_PROVISION_AGENT_INTERFACE,
+ "DisplayString");
+
+ builder = l_dbus_message_builder_new(msg);
+ l_dbus_message_builder_append_basic(builder, 's', str);
+ l_dbus_message_builder_finalize(builder);
+ l_dbus_message_builder_destroy(builder);
+
+ l_debug("Send DisplayString request to %s %s",
+ agent->owner, agent->path);
+
+ l_dbus_send_with_reply(dbus_get_bus(), msg, simple_reply, agent,
NULL);
- return true;
+ agent->req->msg = l_dbus_message_ref(msg);
+
+ return MESH_ERROR_NONE;
+
}
-static bool request_ascii(uint16_t len)
+mesh_error_t mesh_agent_display_number(struct mesh_agent *agent, bool initiator,
+ uint8_t action, uint32_t count,
+ mesh_agent_cb_t cb, void *user_data)
{
- if (len > MAX_ASCII_OOB_LEN)
- return false;
+ const char *str_type;
+ agent_request_type_t type;
+
+ type = action;
+
+ if (initiator)
+ type = action + MESH_AGENT_REQUEST_PUSH;
+
+ if (type >= L_ARRAY_SIZE(cap_table))
+ return MESH_ERROR_INVALID_ARGS;
- bt_shell_printf("Request ASCII key (max characters %d)\n", len);
- bt_shell_prompt_input("mesh", "Enter key (ascii string):",
- response_ascii, NULL);
+ str_type = cap_table[type].action;
- return true;
+ return output_request(agent, str_type, type, count, cb, user_data);
}
-bool agent_input_request(enum oob_type type, uint16_t max_len,
- agent_input_cb cb, void *user_data)
+mesh_error_t mesh_agent_prompt_number(struct mesh_agent *agent, bool initiator,
+ uint8_t action,
+ mesh_agent_number_cb_t cb,
+ void *user_data)
{
- bool result;
+ const char *str_type;
+ agent_request_type_t type;
- if (pending_request.type != NONE)
- return false;
+ type = action;
- switch (type) {
- case HEXADECIMAL:
- result = request_hexadecimal(max_len);
- break;
- case DECIMAL:
- result = request_decimal(max_len);
- break;
- case ASCII:
- result = request_ascii(max_len);
- break;
- case NONE:
- case OUTPUT:
- default:
- return false;
- };
+ if (!initiator)
+ type = action + MESH_AGENT_REQUEST_PUSH;
- if (result) {
- pending_request.type = type;
- pending_request.len = max_len;
- pending_request.cb = cb;
- pending_request.user_data = user_data;
+ if (type >= L_ARRAY_SIZE(cap_table))
+ return MESH_ERROR_INVALID_ARGS;
- return true;
- }
+ str_type = cap_table[type].action;
+
+ return prompt_input(agent, str_type, type, true, cb, user_data);
+}
- return false;
+mesh_error_t mesh_agent_prompt_alpha(struct mesh_agent *agent,
+ mesh_agent_key_cb_t cb, void *user_data)
+{
+ return prompt_input(agent, "in-alpha", MESH_AGENT_REQUEST_IN_ALPHA,
+ false, cb, user_data);
}
-static void response_output(const char *input, void *user_data)
+mesh_error_t mesh_agent_request_static(struct mesh_agent *agent,
+ mesh_agent_key_cb_t cb, void *user_data)
{
- reset_input_request();
+ return prompt_input(agent, "static-oob", MESH_AGENT_REQUEST_STATIC_OOB,
+ false, cb, user_data);
}
-bool agent_output_request(const char *str)
+mesh_error_t mesh_agent_request_private_key(struct mesh_agent *agent,
+ mesh_agent_key_cb_t cb, void *user_data)
{
- if (pending_request.type != NONE)
- return false;
+ return request_key(agent, MESH_AGENT_REQUEST_PRIVATE_KEY, cb,
+ user_data);
- pending_request.type = OUTPUT;
- bt_shell_prompt_input("mesh", str, response_output, NULL);
- return true;
}
-void agent_output_request_cancel(void)
+mesh_error_t mesh_agent_request_public_key(struct mesh_agent *agent,
+ mesh_agent_key_cb_t cb, void *user_data)
{
- if (pending_request.type != OUTPUT)
+ return request_key(agent, MESH_AGENT_REQUEST_PUBLIC_KEY, cb,
+ user_data);
+}
+
+void mesh_agent_cancel(struct mesh_agent *agent)
+{
+ struct l_dbus *dbus = dbus_get_bus();
+ struct l_dbus_message *msg;
+
+ if (!l_queue_find(agents, simple_match, agent))
return;
- pending_request.type = NONE;
- bt_shell_release_prompt("");
+ msg = l_dbus_message_new_method_call(dbus, agent->owner, agent->path,
+ MESH_PROVISION_AGENT_INTERFACE,
+ "Cancel");
+ l_dbus_send(dbus, msg);
}
diff --git a/mesh/agent.h b/mesh/agent.h
index 6fb475691..d90e1c17d 100644
--- a/mesh/agent.h
+++ b/mesh/agent.h
@@ -2,7 +2,7 @@
*
* BlueZ - Bluetooth protocol stack for Linux
*
- * Copyright (C) 2017 Intel Corporation. All rights reserved.
+ * Copyright (C) 2018 Intel Corporation. All rights reserved.
*
*
* This library is free software; you can redistribute it and/or
@@ -18,25 +18,56 @@
*
*/
-#define MAX_HEXADECIMAL_OOB_LEN 128
-#define DECIMAL_OOB_LEN 4
-#define MAX_ASCII_OOB_LEN 16
+struct mesh_agent;
-enum oob_type {
- NONE,
- HEXADECIMAL,
- DECIMAL,
- ASCII,
- OUTPUT,
-} oob_type_t;
+struct mesh_agent_prov_caps {
+ uint32_t uri_hash;
+ uint16_t oob_info;
+ uint16_t output_action;
+ uint16_t input_action;
+ uint8_t pub_type;
+ uint8_t static_type;
+ uint8_t output_size;
+ uint8_t input_size;
+};
-typedef void (*agent_input_cb)(enum oob_type type, void *input, uint16_t len,
+typedef void (*mesh_agent_cb_t) (void *user_data, mesh_error_t err);
+
+typedef void (*mesh_agent_key_cb_t) (void *user_data, mesh_error_t err,
+ uint8_t *key, uint32_t len);
+
+typedef void (*mesh_agent_number_cb_t) (void *user_data,
+ mesh_error_t err, uint32_t number);
+
+void mesh_agent_init(void);
+void mesh_agent_cleanup(void);
+struct mesh_agent *mesh_agent_create(const char *path, const char *owner,
+ struct l_dbus_message_iter *properties);
+
+void mesh_agent_remove(struct mesh_agent *agent);
+void mesh_agent_cancel(struct mesh_agent *agent);
+
+struct mesh_agent_prov_caps *mesh_agent_get_caps(struct mesh_agent *agent);
+
+mesh_error_t mesh_agent_display_number(struct mesh_agent *agent, bool initiator,
+ uint8_t action, uint32_t count,
+ mesh_agent_cb_t cb, void *user_data);
+mesh_error_t mesh_agent_prompt_number(struct mesh_agent *agent, bool initiator,
+ uint8_t action,
+ mesh_agent_number_cb_t cb,
+ void *user_data);
+mesh_error_t mesh_agent_prompt_alpha(struct mesh_agent *agent,
+ mesh_agent_key_cb_t cb,
+ void *user_data);
+mesh_error_t mesh_agent_request_static(struct mesh_agent *agent,
+ mesh_agent_key_cb_t cb,
+ void *user_data);
+mesh_error_t mesh_agent_request_private_key(struct mesh_agent *agent,
+ mesh_agent_key_cb_t cb,
+ void *user_data);
+mesh_error_t mesh_agent_request_public_key(struct mesh_agent *agent,
+ mesh_agent_key_cb_t cb,
void *user_data);
-bool agent_input_request(enum oob_type type, uint16_t max_len,
- agent_input_cb cb, void *user_data);
-
-bool agent_output_request(const char *str);
-void agent_output_request_cancel(void);
-bool agent_completion(void);
-bool agent_input(const char *input);
-void agent_release(void);
+mesh_error_t mesh_agent_display_string(struct mesh_agent *agent,
+ const char *str, mesh_agent_cb_t cb,
+ void *user_data);
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 22/30] mesh: restructure App Key storage
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (20 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 21/30] mesh: DBUS interface for Provisioning Agent Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 23/30] mesh: Clean-up Comment style Brian Gix
` (7 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/appkey.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/mesh/appkey.c b/mesh/appkey.c
index 3d445d217..c4ebf16b6 100644
--- a/mesh/appkey.c
+++ b/mesh/appkey.c
@@ -31,7 +31,7 @@
#include "mesh/node.h"
#include "mesh/net.h"
#include "mesh/crypto.h"
-#include "mesh/display.h"
+#include "mesh/util.h"
#include "mesh/model.h"
#include "mesh/storage.h"
#include "mesh/appkey.h"
@@ -206,12 +206,12 @@ bool appkey_msg_in_replay_cache(struct mesh_net *net, uint16_t idx,
}
if (seq < msg->seq) {
- l_info("Ignoring packet with lower sequence number");
+ l_debug("Ignoring packet with lower sequence number");
return true;
}
if (seq == msg->seq) {
- l_info("Message already processed (duplicate)");
+ l_debug("Message already processed (duplicate)");
return true;
}
@@ -302,6 +302,7 @@ bool appkey_key_init(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,
return false;
key->net_idx = net_idx;
+ key->app_idx = app_idx;
if (key_value && !set_key(key, app_idx, key_value, false))
return false;
@@ -392,14 +393,14 @@ int appkey_key_add(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,
return MESH_STATUS_SUCCESS;
if (!update) {
- l_info("Failed to add key: index already stored %x",
+ l_debug("Failed to add key: index already stored %x",
(net_idx << 16) | app_idx);
return MESH_STATUS_IDX_ALREADY_STORED;
}
}
if (!key) {
- if (l_queue_length(app_keys) <= MAX_APP_KEYS)
+ if (!(l_queue_length(app_keys) < MAX_APP_KEYS))
return MESH_STATUS_INSUFF_RESOURCES;
key = app_key_new();
@@ -411,7 +412,7 @@ int appkey_key_add(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,
return MESH_STATUS_INSUFF_RESOURCES;
}
- if (!storage_local_app_key_add(net, net_idx, app_idx, new_key,
+ if (!storage_app_key_add(net, net_idx, app_idx, new_key,
false)) {
appkey_key_free(key);
return MESH_STATUS_STORAGE_FAIL;
@@ -424,7 +425,7 @@ int appkey_key_add(struct mesh_net *net, uint16_t net_idx, uint16_t app_idx,
if (!set_key(key, app_idx, new_key, true))
return MESH_STATUS_INSUFF_RESOURCES;
- if (!storage_local_app_key_add(net, net_idx, app_idx, new_key,
+ if (!storage_app_key_add(net, net_idx, app_idx, new_key,
true))
return MESH_STATUS_STORAGE_FAIL;
}
@@ -457,7 +458,7 @@ int appkey_key_delete(struct mesh_net *net, uint16_t net_idx,
l_queue_remove(app_keys, key);
appkey_key_free(key);
- if (!storage_local_app_key_del(net, net_idx, app_idx))
+ if (!storage_app_key_del(net, net_idx, app_idx))
return MESH_STATUS_STORAGE_FAIL;
return MESH_STATUS_SUCCESS;
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 23/30] mesh: Clean-up Comment style
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (21 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 22/30] mesh: restructure App Key storage Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 24/30] mesh: Update for DBus API and multi-node support Brian Gix
` (6 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
mesh/friend.c | 76 +++++++++++++++++++++++++++++------------------------------
1 file changed, 38 insertions(+), 38 deletions(-)
diff --git a/mesh/friend.c b/mesh/friend.c
index 9ce499463..d17fde084 100644
--- a/mesh/friend.c
+++ b/mesh/friend.c
@@ -34,7 +34,7 @@
#include "mesh/net.h"
#include "mesh/crypto.h"
#include "mesh/model.h"
-#include "mesh/display.h"
+#include "mesh/util.h"
#include "mesh/friend.h"
@@ -78,7 +78,7 @@ static void response_timeout(struct l_timeout *timeout, void *user_data)
struct frnd_negotiation *neg = user_data;
/* LPN did not choose us */
- l_info("Did not win negotiation for %4.4x", neg->low_power_node);
+ l_debug("Did not win negotiation for %4.4x", neg->low_power_node);
net_key_unref(neg->key_id);
l_queue_remove(frnd_negotiations, neg);
@@ -177,13 +177,13 @@ void friend_request(struct mesh_net *net, uint16_t src,
uint8_t minCache = (minReq >> 0) & 7;
int32_t rsp_delay;
- l_info("RSSI of Request: %d dbm", rssi);
- l_info("Delay: %d ms", delay);
- l_info("Poll Timeout of Request: %d ms", timeout * 100);
- l_info("Previous Friend: %4.4x", prev);
- l_info("Num Elem: %2.2x", num_ele);
- l_info("Cache Requested: %d", cache_size(minCache));
- l_info("Cache to offer: %d", frnd_cache_size);
+ l_debug("RSSI of Request: %d dbm", rssi);
+ l_debug("Delay: %d ms", delay);
+ l_debug("Poll Timeout of Request: %d ms", timeout * 100);
+ l_debug("Previous Friend: %4.4x", prev);
+ l_debug("Num Elem: %2.2x", num_ele);
+ l_debug("Cache Requested: %d", cache_size(minCache));
+ l_debug("Cache to offer: %d", frnd_cache_size);
/* Determine our own suitability before
* deciding to participate in negotiation
@@ -224,7 +224,7 @@ void friend_request(struct mesh_net *net, uint16_t src,
* of 1, bit zero and additional 0.5
*/
rsp_delay = -(rssi * scaling[rssiScale]);
- l_info("RSSI Factor: %d ms", rsp_delay / 10);
+ l_debug("RSSI Factor: %d ms", rsp_delay / 10);
/* Relay Window (Positive Factor, larger values == more time)
* Scaling factor 0-3 == multiplier of 1.0 - 2.5
@@ -232,7 +232,7 @@ void friend_request(struct mesh_net *net, uint16_t src,
* of 1, bit zero and additional 0.5
*/
rsp_delay += frnd_relay_window * scaling[winScale];
- l_info("Win Size Factor: %d ms",
+ l_debug("Win Size Factor: %d ms",
(frnd_relay_window * scaling[winScale]) / 10);
/* Normalize to ms */
@@ -244,7 +244,7 @@ void friend_request(struct mesh_net *net, uint16_t src,
else if (rsp_delay > MAX_RESP_DELAY)
rsp_delay = MAX_RESP_DELAY;
- l_info("Total Response Delay: %d ms", rsp_delay);
+ l_debug("Total Response Delay: %d ms", rsp_delay);
/* Add in 100ms delay before start of "Offer Period" */
rsp_delay += RESPONSE_DELAY;
@@ -261,7 +261,7 @@ void friend_clear_confirm(struct mesh_net *net, uint16_t src,
struct frnd_negotiation *neg = l_queue_remove_if(frnd_negotiations,
match_by_lpn, L_UINT_TO_PTR(lpn));
- l_info("Friend Clear confirmed %4.4x (cnt %4.4x)", lpn, lpnCounter);
+ l_debug("Friend Clear confirmed %4.4x (cnt %4.4x)", lpn, lpnCounter);
if (!neg)
return;
@@ -276,7 +276,7 @@ static void friend_poll_timeout(struct l_timeout *timeout, void *user_data)
struct mesh_friend *frnd = user_data;
if (mesh_friend_clear(frnd->net, frnd))
- l_info("Friend Poll Timeout %4.4x", frnd->dst);
+ l_debug("Friend Poll Timeout %4.4x", frnd->dst);
l_timeout_remove(frnd->timeout);
frnd->timeout = NULL;
@@ -343,7 +343,7 @@ void friend_clear(struct mesh_net *net, uint16_t src, uint16_t lpn,
return;
}
- l_info("Friend Cleared %4.4x (%4.4x)", lpn, lpnCounter);
+ l_debug("Friend Cleared %4.4x (%4.4x)", lpn, lpnCounter);
l_put_be16(lpn, msg + 1);
l_put_be16(lpnCounter, msg + 3);
@@ -369,11 +369,11 @@ static void clear_retry(struct l_timeout *timeout, void *user_data)
if (secs && ((secs << 1) < neg->poll_timeout/10)) {
neg->receive_delay++;
- l_info("Try FRND_CLR again in %d seconds (total timeout %d)",
+ l_debug("Try FRND_CLR again in %d seconds (total timeout %d)",
secs, neg->poll_timeout/10);
l_timeout_modify(neg->timeout, secs);
} else {
- l_info("FRND_CLR timed out %d", secs);
+ l_debug("FRND_CLR timed out %d", secs);
l_timeout_remove(timeout);
l_queue_remove(frnd_negotiations, neg);
l_free(neg);
@@ -407,7 +407,7 @@ static void friend_delay_rsp(struct l_timeout *timeout, void *user_data)
seqZero &= SEQ_ZERO_MASK;
- l_info("Fwd ACK pkt %6.6x-%8.8x",
+ l_debug("Fwd ACK pkt %6.6x-%8.8x",
pkt->u.one[0].seq,
pkt->iv_index);
@@ -420,7 +420,7 @@ static void friend_delay_rsp(struct l_timeout *timeout, void *user_data)
} else {
- l_info("Fwd CTL pkt %6.6x-%8.8x",
+ l_debug("Fwd CTL pkt %6.6x-%8.8x",
pkt->u.one[0].seq,
pkt->iv_index);
@@ -442,7 +442,7 @@ static void friend_delay_rsp(struct l_timeout *timeout, void *user_data)
else
len = pkt->last_len;
- l_info("Fwd FRND pkt %6.6x",
+ l_debug("Fwd FRND pkt %6.6x",
pkt->u.s12[pkt->cnt_out].seq);
print_packet("Frnd-Msg", pkt->u.s12[pkt->cnt_out].data, len);
@@ -462,7 +462,7 @@ static void friend_delay_rsp(struct l_timeout *timeout, void *user_data)
update:
/* No More Data -- send Update message with md = false */
net_seq = mesh_net_get_seq_num(net);
- l_info("Fwd FRND UPDATE %6.6x with MD == 0", net_seq);
+ l_debug("Fwd FRND UPDATE %6.6x with MD == 0", net_seq);
frnd->last = frnd->seq;
mesh_net_get_snb_state(net, upd + 1, &iv_index);
@@ -488,7 +488,7 @@ void friend_poll(struct mesh_net *net, uint16_t src, bool seq,
if (neg && !neg->clearing) {
uint8_t msg[5] = { NET_OP_FRND_CLEAR };
- l_info("Won negotiation for %4.4x", neg->low_power_node);
+ l_debug("Won negotiation for %4.4x", neg->low_power_node);
/* This call will clean-up and replace if already friends */
frnd = mesh_friend_new(net, src, neg->num_ele,
@@ -695,7 +695,7 @@ void frnd_offer(struct mesh_net *net, uint16_t src, uint8_t window,
{
struct frnd_offers *offer;
- l_info("RSSI of Offer: %d dbm", l_rssi);
+ l_debug("RSSI of Offer: %d dbm", l_rssi);
/* Ignore RFU window value 0 */
if (window == 0)
@@ -735,7 +735,7 @@ static void frnd_negotiated_to(struct l_timeout *timeout, void *user_data)
{
struct mesh_net *net = user_data;
- l_info("frnd_negotiated_to");
+ l_debug("frnd_negotiated_to");
if (!mesh_net_get_friend(net)) {
l_timeout_remove(poll_period_to);
poll_period_to = NULL;
@@ -776,7 +776,7 @@ void frnd_poll(struct mesh_net *net, bool retry)
seq = !seq;
mesh_net_set_frnd_seq(net, seq);
} else if (!(poll_cnt--)) {
- l_info("Lost Friendship with %4.4x", old_friend);
+ l_debug("Lost Friendship with %4.4x", old_friend);
l_timeout_remove(poll_period_to);
poll_period_to = NULL;
frnd_poll_cancel(net);
@@ -790,7 +790,7 @@ void frnd_poll(struct mesh_net *net, bool retry)
if (poll_retry_to)
l_timeout_remove(poll_retry_to);
- l_info("TX-FRIEND POLL %d", seq);
+ l_debug("TX-FRIEND POLL %d", seq);
msg[1] = seq;
net_seq = mesh_net_get_seq_num(net);
mesh_net_transport_send(net, key_id, true,
@@ -858,7 +858,7 @@ static void req_timeout(struct l_timeout *timeout, void *user_data)
l_free(best);
return;
} else if (!best) {
- l_info("No Offers Received");
+ l_debug("No Offers Received");
return;
}
@@ -884,7 +884,7 @@ static void req_timeout(struct l_timeout *timeout, void *user_data)
old_keys_only:
- l_info("Winning offer %4.4x RSSI: %ddb Window: %dms Cache sz: %d",
+ l_debug("Winning offer %4.4x RSSI: %ddb Window: %dms Cache sz: %d",
best->src, best->local_rssi,
best->window, best->cache);
@@ -930,23 +930,23 @@ void frnd_request_friend(struct mesh_net *net, uint8_t cache,
offers = l_queue_new();
msg[n++] = NET_OP_FRND_REQUEST;
- msg[n] = cache & 0x07; // MinRequirements - Cache
- msg[n++] |= (offer_delay & 0x0f) << 3; // Offer Delay
- poll_period_ms = (timeout * 300) / 4; // 3/4 of the time in ms
- l_put_be32(timeout, msg + n); // PollTimeout
- msg[n++] = delay; // ReceiveDelay
+ msg[n] = cache & 0x07; /* MinRequirements - Cache */
+ msg[n++] |= (offer_delay & 0x0f) << 3; /* Offer Delay */
+ poll_period_ms = (timeout * 300) / 4; /* 3/4 of the time in ms */
+ l_put_be32(timeout, msg + n); /* PollTimeout */
+ msg[n++] = delay; /* ReceiveDelay */
n += 3;
- l_put_be16(old_friend, msg + n); // PreviousAddress
+ l_put_be16(old_friend, msg + n); /* PreviousAddress */
n += 2;
- msg[n++] = mesh_net_get_num_ele(net); // NumElements
- l_put_be16(cnt + 1, msg + n); // Next counter
+ msg[n++] = mesh_net_get_num_ele(net); /* NumElements */
+ l_put_be16(cnt + 1, msg + n); /* Next counter */
n += 2;
print_packet("Tx-NET_OP_FRND_REQUEST", msg, n);
mesh_net_transport_send(net, 0, false,
mesh_net_get_iv_index(net), 0,
0, 0, FRIENDS_ADDRESS,
msg, n);
- l_timeout_create_ms(1000, req_timeout, net, NULL); // 1000 ms
+ l_timeout_create_ms(1000, req_timeout, net, NULL); /* 1000 ms */
mesh_net_set_friend(net, 0);
cnt++;
}
@@ -1036,7 +1036,7 @@ void frnd_key_refresh(struct mesh_net *net, uint8_t phase)
case 0:
case 3:
if (new_lpn_id) {
- l_info("LPN Retiring KeySet %d", lpn_key_id);
+ l_debug("LPN Retiring KeySet %d", lpn_key_id);
net_key_unref(lpn_key_id);
lpn_key_id = new_lpn_id;
}
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 24/30] mesh: Update for DBus API and multi-node support
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (22 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 23/30] mesh: Clean-up Comment style Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 25/30] mesh: Add default location for Mesh Node storage Brian Gix
` (5 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/main.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 66 insertions(+), 7 deletions(-)
diff --git a/mesh/main.c b/mesh/main.c
index 173f57a8f..95a66cc9d 100644
--- a/mesh/main.c
+++ b/mesh/main.c
@@ -33,11 +33,14 @@
#include <sys/stat.h>
#include <ell/ell.h>
+#include <dbus/dbus.h>
+
#include "lib/bluetooth.h"
#include "lib/mgmt.h"
#include "mesh/mesh.h"
#include "mesh/net.h"
+#include "mesh/dbus.h"
#include "mesh/storage.h"
static const struct option main_options[] = {
@@ -56,12 +59,46 @@ static void usage(void)
"\tmeshd [options]\n");
l_info("Options:\n"
"\t--index <hcinum> Use specified controller\n"
- "\t--config Configuration file\n"
+ "\t--config Configuration directory\n"
"\t--nodetach Run in foreground\n"
"\t--debug Enable debug output\n"
"\t--help Show %s information\n", __func__);
}
+static void do_debug(const char *str, void *user_data)
+{
+ const char *prefix = user_data;
+
+ l_info("%s%s", prefix, str);
+}
+
+static void request_name_callback(struct l_dbus *dbus, bool success,
+ bool queued, void *user_data)
+{
+ l_info("Request name %s",
+ success ? "success": "failed");
+
+ if (success)
+ dbus_init(dbus);
+ else
+ l_main_quit();
+}
+
+static void ready_callback(void *user_data)
+{
+ struct l_dbus *dbus = user_data;
+
+ l_info("D-Bus ready");
+ l_dbus_name_acquire(dbus, BLUEZ_MESH_NAME, false, false, false,
+ request_name_callback, NULL);
+
+}
+
+static void disconnect_callback(void *user_data)
+{
+ l_main_quit();
+}
+
static void signal_handler(uint32_t signo, void *user_data)
{
static bool terminated;
@@ -78,8 +115,9 @@ int main(int argc, char *argv[])
{
int status;
bool detached = true;
- struct bt_mesh *mesh = NULL;
- const char *config_file = NULL;
+ bool dbus_debug = false;
+ struct l_dbus *dbus = NULL;
+ const char *config_dir = NULL;
int index = MGMT_INDEX_NONE;
if (!l_main_init())
@@ -91,7 +129,7 @@ int main(int argc, char *argv[])
int opt;
const char *str;
- opt = getopt_long(argc, argv, "i:c:ndh", main_options, NULL);
+ opt = getopt_long(argc, argv, "i:c:ndbh", main_options, NULL);
if (opt < 0)
break;
@@ -117,7 +155,10 @@ int main(int argc, char *argv[])
l_debug_enable("*");
break;
case 'c':
- config_file = optarg;
+ config_dir = optarg;
+ break;
+ case 'b':
+ dbus_debug = true;
break;
case 'h':
usage();
@@ -130,7 +171,7 @@ int main(int argc, char *argv[])
}
}
- if (!mesh_new(index, config_file)) {
+ if (!mesh_init(index, config_dir)) {
l_error("Failed to initialize mesh");
status = EXIT_FAILURE;
goto done;
@@ -138,6 +179,24 @@ int main(int argc, char *argv[])
umask(0077);
+ dbus = l_dbus_new_default(L_DBUS_SYSTEM_BUS);
+ if (!dbus) {
+ l_error("unable to connect to D-Bus");
+ status = EXIT_FAILURE;
+ goto done;
+ }
+
+ if (dbus_debug)
+ l_dbus_set_debug(dbus, do_debug, "[DBUS] ", NULL);
+ l_dbus_set_ready_handler(dbus, ready_callback, dbus, NULL);
+ l_dbus_set_disconnect_handler(dbus, disconnect_callback, NULL, NULL);
+
+ if (!l_dbus_object_manager_enable(dbus)) {
+ l_error("Failed to enable Object Manager");
+ status = EXIT_FAILURE;
+ goto done;
+ }
+
if (detached) {
if (daemon(0, 0)) {
perror("Failed to start meshd daemon");
@@ -149,8 +208,8 @@ int main(int argc, char *argv[])
status = l_main_run_with_signal(signal_handler, NULL);
done:
- mesh_unref(mesh);
mesh_cleanup();
+ l_dbus_destroy(dbus);
l_main_exit();
return status;
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 25/30] mesh: Add default location for Mesh Node storage
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (23 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 24/30] mesh: Update for DBus API and multi-node support Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 26/30] mesh: Add structural changes to for mesh Brian Gix
` (4 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
configure.ac | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/configure.ac b/configure.ac
index 1a095a352..901d51e0f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -364,6 +364,11 @@ AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}",
[Directory for the configuration files])
AC_SUBST(CONFIGDIR, "${configdir}")
+if (test "${enable_mesh}" = "yes"); then
+ AC_DEFINE_UNQUOTED(MESH_STORAGEDIR, "${storagedir}/mesh",
+ [Directory for the storage files])
+fi
+
AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android],
[enable BlueZ for Android]),
[enable_android=${enableval}])
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 26/30] mesh: Add structural changes to for mesh
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (24 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 25/30] mesh: Add default location for Mesh Node storage Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 27/30] mesh: Sample Provisioning Agent Brian Gix
` (3 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
Makefile.mesh | 27 +++++++++++++++++----------
1 file changed, 17 insertions(+), 10 deletions(-)
diff --git a/Makefile.mesh b/Makefile.mesh
index a9c387e08..65310860f 100644
--- a/Makefile.mesh
+++ b/Makefile.mesh
@@ -3,35 +3,42 @@ if MESH
mesh_sources = mesh/mesh.h mesh/mesh.c \
mesh/net_keys.h mesh/net_keys.c \
mesh/mesh-io.h mesh/mesh-io.c \
- mesh/mesh-io-api.h \
+ mesh/error.h mesh/mesh-io-api.h \
mesh/mesh-io-generic.h \
mesh/mesh-io-generic.c \
mesh/storage.h mesh/storage.c \
mesh/net.h mesh/net.c \
- mesh/display.h mesh/display.c \
mesh/crypto.h mesh/crypto.c \
mesh/friend.h mesh/friend.c \
mesh/appkey.h mesh/appkey.c \
mesh/node.h mesh/node.c \
- mesh/prov.h mesh/prov.c \
- mesh/provision.h mesh/provision.c \
+ mesh/provision.h mesh/prov.h \
mesh/model.h mesh/model.c \
mesh/cfgmod.h mesh/cfgmod-server.c \
mesh/mesh-db.h mesh/mesh-db.c \
mesh/util.h mesh/util.c \
- mesh/mesh-defs.h
+ mesh/dbus.h mesh/dbus.c \
+ mesh/agent.h mesh/agent.c \
+ mesh/prov-acceptor.c mesh/prov-initiator.c \
+ mesh/pb-adv.c mesh/mesh-defs.h
libexec_PROGRAMS += mesh/meshd
mesh_meshd_SOURCES = $(mesh_sources) mesh/main.c
mesh_meshd_LDADD = src/libshared-ell.la $(ell_ldadd) -ljson-c
mesh_meshd_DEPENDENCIES = $(ell_dependencies)
-noinst_PROGRAMS += mesh/btmesh
-
-mesh_btmesh_SOURCES = $(mesh_sources) mesh/agent.h \
- mesh/agent.c \
- mesh/btmesh.c
mesh_btmesh_LDADD = src/libshared-mainloop.la $(ell_ldadd) -lreadline -ljson-c
mesh_btmesh_DEPENDENCIES = $(ell_dependencies)
+#
+# noinst_PROGRAMS += mesh/btmesh
+#
+# mesh_btmesh_SOURCES = $(mesh_sources) \
+# mesh/btmesh.c
+#
+#mesh_btmesh_LDADD = src/shared/ecc.lo src/shared/queue.lo src/shared/io-ell.lo \
+# src/shared/util.lo src/shared/hci.lo src/shared/mgmt.lo \
+# src/libshared-mainloop.la \
+# -lreadline @ELL_LIBS@ -ljson-c
+
endif
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 27/30] mesh: Sample Provisioning Agent
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (25 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 26/30] mesh: Add structural changes to for mesh Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 28/30] mesh: Sample On/Off Client and Server Brian Gix
` (2 subsequent siblings)
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/test/agent.py | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100755 mesh/test/agent.py
diff --git a/mesh/test/agent.py b/mesh/test/agent.py
new file mode 100755
index 000000000..22c92f952
--- /dev/null
+++ b/mesh/test/agent.py
@@ -0,0 +1,40 @@
+#!/usr/bin/python
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+
+AGENT_IFACE = 'org.bluez.mesh.ProvisionAgent1'
+AGENT_PATH = "/mesh/test/agent"
+
+bus = None
+
+class Agent(dbus.service.Object):
+ def __init__(self, bus):
+ self.path = AGENT_PATH
+ self.bus = bus
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_properties(self):
+ caps = []
+ oob = []
+ caps.append('out-numeric')
+ oob.append('other')
+ return {
+ AGENT_IFACE: {
+ 'Capabilities': dbus.Array(caps, 's'),
+ 'OutOfBandInfo': dbus.Array(oob, 's')
+ }
+ }
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ @dbus.service.method(AGENT_IFACE, in_signature="", out_signature="")
+ def Cancel(self):
+ print("Cancel")
+
+ @dbus.service.method(AGENT_IFACE, in_signature="su", out_signature="")
+ def DisplayNumeric(self, type, value):
+ print("DisplayNumeric type=", type, " number=", value)
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 28/30] mesh: Sample On/Off Client and Server
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (26 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 27/30] mesh: Sample Provisioning Agent Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 29/30] mesh: Sample Mesh Joiner (provision acceptor) Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 30/30] mesh: Enable building Mesh Daemon Brian Gix
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/test/example-onoff-client | 288 ++++++++++++++++++++++++++++++++
mesh/test/example-onoff-server | 365 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 653 insertions(+)
create mode 100644 mesh/test/example-onoff-client
create mode 100644 mesh/test/example-onoff-server
diff --git a/mesh/test/example-onoff-client b/mesh/test/example-onoff-client
new file mode 100644
index 000000000..e4a87eb12
--- /dev/null
+++ b/mesh/test/example-onoff-client
@@ -0,0 +1,288 @@
+#!/usr/bin/env python3
+
+import sys
+import struct
+import numpy
+import dbus
+import dbus.service
+import dbus.exceptions
+
+try:
+ from gi.repository import GObject
+except ImportError:
+ import gobject as GObject
+from dbus.mainloop.glib import DBusGMainLoop
+
+MESH_SERVICE_NAME = 'org.bluez.mesh'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+
+MESH_NETWORK_IFACE = 'org.bluez.mesh.Network1'
+MESH_NODE_IFACE = 'org.bluez.mesh.Node1'
+MESH_ELEMENT_IFACE = 'org.bluez.mesh.Element1'
+
+VENDOR_ID_NONE = 0xffff
+
+app = None
+bus = None
+mainloop = None
+node = None
+token = numpy.uint64(0x76bd4f2372477600)
+
+def unwrap(item):
+ if isinstance(item, dbus.Boolean):
+ return bool(item)
+ if isinstance(item, (dbus.UInt16, dbus.Int16, dbus.UInt32, dbus.Int32,
+ dbus.UInt64, dbus.Int64)):
+ return int(item)
+ if isinstance(item, dbus.Byte):
+ return bytes([int(item)])
+ if isinstance(item, dbus.String):
+ return item
+ if isinstance(item, (dbus.Array, list, tuple)):
+ return [unwrap(x) for x in item]
+ if isinstance(item, (dbus.Dictionary, dict)):
+ return dict([(unwrap(x), unwrap(y)) for x, y in item.items()])
+
+ print('Dictionary item not handled')
+ print(type(item))
+ return item
+
+def attach_app_cb(node_path, dict_array):
+ print('Mesh application registered ', node_path)
+ print(type(node_path))
+ print(type(dict_array))
+ print(dict_array)
+
+ els = unwrap(dict_array)
+ print("Get Elements")
+ for el in els:
+ print(el)
+ idx = struct.unpack('b', el[0])[0]
+ print('Configuration for Element ', end='')
+ print(idx)
+ models = el[1]
+
+ element = app.get_element(idx)
+ element.set_model_config(models)
+
+ obj = bus.get_object(MESH_SERVICE_NAME, node_path)
+ global node
+ node = dbus.Interface(obj, MESH_NODE_IFACE)
+
+def error_cb(error):
+ print('D-Bus call failed: ' + str(error))
+
+def generic_reply_cb():
+ print('D-Bus call done')
+
+def interfaces_removed_cb(object_path, interfaces):
+ if not mesh_net:
+ return
+
+ if object_path == mesh_net[2]:
+ print('Service was removed')
+ mainloop.quit()
+
+class Application(dbus.service.Object):
+
+ def __init__(self, bus):
+ self.path = '/example'
+ self.elements = []
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_element(self, element):
+ self.elements.append(element)
+
+ def get_element(self, idx):
+ for ele in self.elements:
+ if ele.get_index() == idx:
+ return ele
+
+ @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}')
+ def GetManagedObjects(self):
+ response = {}
+ print('GetManagedObjects')
+ for element in self.elements:
+ response[element.get_path()] = element.get_properties()
+ return response
+
+class Element(dbus.service.Object):
+ PATH_BASE = '/example/ele'
+
+ def __init__(self, bus, index):
+ self.path = self.PATH_BASE + format(index, '02x')
+ print(self.path)
+ self.models = []
+ self.bus = bus
+ self.index = index
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def _get_sig_models(self):
+ ids = []
+ for model in self.models:
+ id = model.get_id()
+ vendor = model.get_vendor()
+ if vendor == VENDOR_ID_NONE:
+ ids.append(id)
+ return ids
+
+ def get_properties(self):
+ return {
+ MESH_ELEMENT_IFACE: {
+ 'Index': dbus.Byte(self.index),
+ 'Models': dbus.Array(
+ self._get_sig_models(), signature='q')
+ }
+ }
+
+ def add_model(self, model):
+ model.set_path(self.path)
+ self.models.append(model)
+
+ def get_index(self):
+ return self.index
+
+ def set_model_config(self, config):
+ print('Set element models config')
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="qqbay", out_signature="")
+ def MessageReceived(self, source, key, is_sub, data):
+ print('Message Received on Element ', end='')
+ print(self.index)
+ for model in self.models:
+ model.process_message(source, key, data)
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="qa{sv}", out_signature="")
+
+ def UpdateModelConfiguration(self, model_id, config):
+ print('UpdateModelConfig ', end='')
+ print(hex(model_id))
+ for model in self.models:
+ if model_id == model.get_id():
+ model.set_config(config)
+ return
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="", out_signature="")
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+class Model():
+ def __init__(self, model_id):
+ self.cmd_ops = []
+ self.model_id = model_id
+ self.vendor = VENDOR_ID_NONE
+ self.path = None
+
+ def set_path(self, path):
+ self.path = path
+
+ def get_id(self):
+ return self.model_id
+
+ def get_vendor(self):
+ return self.vendor
+
+ def process_message(self, source, key, data):
+ print('Model process message')
+
+ def set_publication(self, period):
+ self.period = period
+
+ def set_bindings(self, bindings):
+ self.bindings = bindings
+
+ def set_config(self, config):
+ if 'Bindings' in config:
+ self.bindings = config.get('Bindings')
+ print('Bindings: ', end='')
+ print(self.bindings)
+ if 'PublicationPeriod' in config:
+ self.set_publication(config.get('PublicationPeriod'))
+ print('Model publication period ', end='')
+ print(self.pub_period, end='')
+ print(' ms')
+
+class OnOffClient(Model):
+ def __init__(self, model_id):
+ Model.__init__(self, model_id)
+ self.cmd_ops = { 0x8201, # get
+ 0x8202, # set
+ 0x8203 } # set unacknowledged
+ print('OnOff Client')
+
+ def _reply_cb(state):
+ print('State ', end='');
+ print(state)
+
+ def _send_message(self, dest, key, data, reply_cb):
+ print('OnOffClient send data')
+ node.Send(self.path, dest, key, data, reply_handler=reply_cb,
+ error_handler=error_cb)
+
+ def get_state(self, dest, key):
+ opcode = 0x8201
+ data = struct.pack('<H', opcode)
+ self._send_message(dest, key, data, self._reply_cb)
+
+ def set_state(self, dest, key, state):
+ opcode = 0x8202
+ data = struct.pack('<HB', opcode, state)
+ self._send_message(dest, key, data, self._reply_cb)
+
+ def process_message(self, source, key, data):
+ print('OnOffClient process message len ', end = '')
+ datalen = len(data)
+ print(datalen)
+
+ if datalen!=3:
+ return
+
+ opcode, state=struct.unpack('<HB',bytes(data))
+ if opcode != 0x8202 :
+ print('Bad opcode ', end='')
+ print(hex(opcode))
+ return
+
+ print('Got state ', end = '')
+ print(hex(state))
+
+def attach_app_error_cb(error):
+ print('Failed to register application: ' + str(error))
+ mainloop.quit()
+
+def main():
+
+ DBusGMainLoop(set_as_default=True)
+
+ global bus
+ bus = dbus.SystemBus()
+ global mainloop
+ global app
+
+ mesh_net = dbus.Interface(bus.get_object(MESH_SERVICE_NAME,
+ "/org/bluez/mesh"),
+ MESH_NETWORK_IFACE)
+ mesh_net.connect_to_signal('InterfacesRemoved', interfaces_removed_cb)
+
+ app = Application(bus)
+ first_ele = Element(bus, 0x00)
+ first_ele.add_model(OnOffClient(0x1001))
+ app.add_element(first_ele)
+
+ mainloop = GObject.MainLoop()
+
+ print('Attach')
+ mesh_net.Attach(app.get_path(), token,
+ reply_handler=attach_app_cb,
+ error_handler=attach_app_error_cb)
+ mainloop.run()
+
+if __name__ == '__main__':
+ main()
diff --git a/mesh/test/example-onoff-server b/mesh/test/example-onoff-server
new file mode 100644
index 000000000..131b6415c
--- /dev/null
+++ b/mesh/test/example-onoff-server
@@ -0,0 +1,365 @@
+#!/usr/bin/env python3
+
+import sys
+import struct
+import numpy
+import dbus
+import dbus.service
+import dbus.exceptions
+
+from threading import Timer
+import time
+
+
+try:
+ from gi.repository import GObject
+except ImportError:
+ import gobject as GObject
+from dbus.mainloop.glib import DBusGMainLoop
+
+MESH_SERVICE_NAME = 'org.bluez.mesh'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+
+MESH_NETWORK_IFACE = 'org.bluez.mesh.Network1'
+MESH_NODE_IFACE = 'org.bluez.mesh.Node1'
+MESH_APPLICATION_IFACE = 'org.bluez.mesh.Application1'
+MESH_ELEMENT_IFACE = 'org.bluez.mesh.Element1'
+
+APP_COMPANY_ID = 0x05f1
+APP_PRODUCT_ID = 0x0001
+APP_VERSION_ID = 0x0001
+
+VENDOR_ID_NONE = 0xffff
+
+app = None
+bus = None
+mainloop = None
+node = None
+
+token = numpy.uint64(0x76bd4f2372476578)
+
+def generic_error_cb(error):
+ print('D-Bus call failed: ' + str(error))
+
+def generic_reply_cb():
+ print('D-Bus call done')
+
+def unwrap(item):
+ if isinstance(item, dbus.Boolean):
+ return bool(item)
+ if isinstance(item, (dbus.UInt16, dbus.Int16, dbus.UInt32, dbus.Int32,
+ dbus.UInt64, dbus.Int64)):
+ return int(item)
+ if isinstance(item, dbus.Byte):
+ return bytes([int(item)])
+ if isinstance(item, dbus.String):
+ return item
+ if isinstance(item, (dbus.Array, list, tuple)):
+ return [unwrap(x) for x in item]
+ if isinstance(item, (dbus.Dictionary, dict)):
+ return dict([(unwrap(x), unwrap(y)) for x, y in item.items()])
+
+ print('Dictionary item not handled')
+ print(type(item))
+ return item
+
+def attach_app_cb(node_path, dict_array):
+ print('Mesh application registered ', node_path)
+
+ obj = bus.get_object(MESH_SERVICE_NAME, node_path)
+
+ global node
+ node = dbus.Interface(obj, MESH_NODE_IFACE)
+
+ els = unwrap(dict_array)
+ print("Get Elements")
+
+ for el in els:
+ idx = struct.unpack('b', el[0])[0]
+ print('Configuration for Element ', end='')
+ print(idx)
+
+ models = el[1]
+ element = app.get_element(idx)
+ element.set_model_config(models)
+
+def interfaces_removed_cb(object_path, interfaces):
+ if not mesh_net:
+ return
+
+ if object_path == mesh_net[2]:
+ print('Service was removed')
+ mainloop.quit()
+
+def send_response(path, dest, key, data):
+ print('send response ', end='')
+ print(data)
+ node.Send(path, dest, key, data, reply_handler=generic_reply_cb,
+ error_handler=generic_error_cb)
+
+def send_publication(path, model_id, data):
+ print('send publication ', end='')
+ print(data)
+ node.Publish(path, model_id, data,
+ reply_handler=generic_reply_cb,
+ error_handler=generic_error_cb)
+
+class PubTimer():
+ def __init__(self):
+ self.seconds = None
+ self.func = None
+ self.thread = None
+ self.busy = False
+
+ def _timeout_cb(self):
+ self.func()
+ self.busy = True
+ self._schedule_timer()
+ self.busy =False
+
+ def _schedule_timer(self):
+ self.thread = Timer(self.seconds, self._timeout_cb)
+ self.thread.start()
+
+ def start(self, seconds, func):
+ self.func = func
+ self.seconds = seconds
+ if not self.busy:
+ self._schedule_timer()
+
+ def cancel(self):
+ print('Cancel timer')
+ if self.thread is not None:
+ print('Cancel thread')
+ self.thread.cancel()
+ self.thread = None
+
+class Application(dbus.service.Object):
+
+ def __init__(self, bus):
+ self.path = '/example'
+ self.elements = []
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_element(self, element):
+ self.elements.append(element)
+
+ def get_element(self, idx):
+ for ele in self.elements:
+ if ele.get_index() == idx:
+ return ele
+
+ def get_properties(self):
+ return {
+ MESH_APPLICATION_IFACE: {
+ 'CompanyID': dbus.UInt16(APP_COMPANY_ID),
+ 'ProductID': dbus.UInt16(APP_PRODUCT_ID),
+ 'VersionID': dbus.UInt16(APP_VERSION_ID)
+ }
+ }
+
+ @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}')
+ def GetManagedObjects(self):
+ response = {}
+ print('GetManagedObjects')
+ response[self.path] = self.get_properties()
+ for element in self.elements:
+ response[element.get_path()] = element.get_properties()
+ return response
+
+class Element(dbus.service.Object):
+ PATH_BASE = '/example/ele'
+
+ def __init__(self, bus, index):
+ self.path = self.PATH_BASE + format(index, '02x')
+ print(self.path)
+ self.models = []
+ self.bus = bus
+ self.index = index
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def _get_sig_models(self):
+ ids = []
+ for model in self.models:
+ id = model.get_id()
+ vendor = model.get_vendor()
+ if vendor == VENDOR_ID_NONE:
+ ids.append(id)
+ return ids
+
+ def get_properties(self):
+ return {
+ MESH_ELEMENT_IFACE: {
+ 'Index': dbus.Byte(self.index),
+ 'Models': dbus.Array(
+ self._get_sig_models(), signature='q')
+ }
+ }
+
+ def add_model(self, model):
+ model.set_path(self.path)
+ self.models.append(model)
+
+ def get_index(self):
+ return self.index
+
+ def set_model_config(self, configs):
+ print('Set element models config')
+ for config in configs:
+ mod_id = config[0]
+ self.UpdateModelConfiguration(mod_id, config[1])
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="qqbay", out_signature="")
+ def MessageReceived(self, source, key, is_sub, data):
+ print('Message Received on Element ', end='')
+ print(self.index)
+ for model in self.models:
+ model.process_message(source, key, data)
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="qa{sv}", out_signature="")
+
+ def UpdateModelConfiguration(self, model_id, config):
+ print('UpdateModelConfig ', end='')
+ print(hex(model_id))
+ for model in self.models:
+ if model_id == model.get_id():
+ model.set_config(config)
+ return
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="", out_signature="")
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+class Model():
+ def __init__(self, model_id):
+ self.cmd_ops = []
+ self.model_id = model_id
+ self.vendor = VENDOR_ID_NONE
+ self.bindings = []
+ self.pub_period = 0
+ self.pub_id = 0
+ self.path = None
+
+ def set_path(self, path):
+ self.path = path
+
+ def get_id(self):
+ return self.model_id
+
+ def get_vendor(self):
+ return self.vendor
+
+ def process_message(self, source, key, data):
+ print('Model process message')
+
+ def set_publication(self, period):
+ self.pub_period = period
+
+ def set_config(self, config):
+ if 'Bindings' in config:
+ self.bindings = config.get('Bindings')
+ print('Bindings: ', end='')
+ print(self.bindings)
+ if 'PublicationPeriod' in config:
+ self.set_publication(config.get('PublicationPeriod'))
+ print('Model publication period ', end='')
+ print(self.pub_period, end='')
+ print(' ms')
+
+class OnOffServer(Model):
+ def __init__(self, model_id):
+ Model.__init__(self, model_id)
+ self.cmd_ops = { 0x8201, # get
+ 0x8202, # set
+ 0x8203 } # set unacknowledged
+
+ print("OnOff Server ", end="")
+ self.state = 0
+ print('State ', end='')
+ self.timer = PubTimer()
+
+ def process_message(self, source, key, data):
+ datalen = len(data)
+ print('OnOff Server process message len ', datalen)
+
+ if datalen!=2 and datalen!=3:
+ return
+
+ if datalen==2:
+ op_tuple=struct.unpack('<H',bytes(data))
+ opcode = op_tuple[0]
+ if opcode != 0x8201:
+ print(hex(opcode))
+ return
+ print('Get state')
+ elif datalen==3:
+ opcode,self.state=struct.unpack('<HB',bytes(data))
+ if opcode != 0x8202 and opcode != 0x8203:
+ print(hex(opcode))
+ return
+ print('Set state: ', end='')
+ print(self.state)
+
+ rsp_data = struct.pack('<HB', 0x8204, self.state)
+ send_response(self.path, source, key, rsp_data)
+
+ def publish(self):
+ print('Publish')
+ data = struct.pack('B', self.state)
+ send_publication(self.path, self.model_id, data)
+
+ def set_publication(self, period):
+ if period == 0:
+ self.pub_period = 0
+ self.timer.cancel()
+ return
+
+ # We do not handle ms in this example
+ if period < 1000:
+ return
+
+ self.pub_period = period
+ self.timer.start(period/1000, self.publish)
+
+def attach_app_error_cb(error):
+ print('Failed to register application: ' + str(error))
+ mainloop.quit()
+
+def main():
+
+ DBusGMainLoop(set_as_default=True)
+
+ global bus
+ bus = dbus.SystemBus()
+ global mainloop
+ global app
+
+ mesh_net = dbus.Interface(bus.get_object(MESH_SERVICE_NAME,
+ "/org/bluez/mesh"),
+ MESH_NETWORK_IFACE)
+ mesh_net.connect_to_signal('InterfacesRemoved', interfaces_removed_cb)
+
+ app = Application(bus)
+ first_ele = Element(bus, 0x00)
+ first_ele.add_model(OnOffServer(0x1000))
+ app.add_element(first_ele)
+
+ mainloop = GObject.MainLoop()
+
+ print('Attach')
+ mesh_net.Attach(app.get_path(), token,
+ reply_handler=attach_app_cb,
+ error_handler=attach_app_error_cb)
+
+ mainloop.run()
+
+if __name__ == '__main__':
+ main()
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 29/30] mesh: Sample Mesh Joiner (provision acceptor)
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (27 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 28/30] mesh: Sample On/Off Client and Server Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 30/30] mesh: Enable building Mesh Daemon Brian Gix
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
From: Inga Stotland <inga.stotland@intel.com>
---
mesh/test/test-join | 408 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 408 insertions(+)
create mode 100644 mesh/test/test-join
diff --git a/mesh/test/test-join b/mesh/test/test-join
new file mode 100644
index 000000000..cdf92a2f1
--- /dev/null
+++ b/mesh/test/test-join
@@ -0,0 +1,408 @@
+#!/usr/bin/env python3
+
+import sys
+import struct
+import numpy
+import dbus
+import dbus.service
+import dbus.exceptions
+
+from threading import Timer
+import time
+
+try:
+ from gi.repository import GObject
+except ImportError:
+ import gobject as GObject
+from dbus.mainloop.glib import DBusGMainLoop
+
+import agent
+
+MESH_SERVICE_NAME = 'org.bluez.mesh'
+DBUS_PROP_IFACE = 'org.freedesktop.DBus.Properties'
+DBUS_OM_IFACE = 'org.freedesktop.DBus.ObjectManager'
+
+MESH_NETWORK_IFACE = 'org.bluez.mesh.Network1'
+MESH_NODE_IFACE = 'org.bluez.mesh.Node1'
+MESH_APPLICATION_IFACE = 'org.bluez.mesh.Application1'
+MESH_ELEMENT_IFACE = 'org.bluez.mesh.Element1'
+
+APP_COMPANY_ID = 0x05f1
+APP_PRODUCT_ID = 0x0001
+APP_VERSION_ID = 0x0001
+
+VENDOR_ID_NONE = 0xffff
+
+mesh_net = None
+app = None
+bus = None
+mainloop = None
+node = None
+
+token = None
+
+def generic_error_cb(error):
+ print('D-Bus call failed: ' + str(error))
+
+def generic_reply_cb():
+ print('D-Bus call done')
+
+def unwrap(item):
+ if isinstance(item, dbus.Boolean):
+ return bool(item)
+ if isinstance(item, (dbus.UInt16, dbus.Int16,
+ dbus.UInt32, dbus.Int32,
+ dbus.UInt64, dbus.Int64)):
+ return int(item)
+ if isinstance(item, dbus.Byte):
+ return bytes([int(item)])
+ if isinstance(item, dbus.String):
+ return item
+ if isinstance(item, (dbus.Array, list, tuple)):
+ return [unwrap(x) for x in item]
+ if isinstance(item, (dbus.Dictionary, dict)):
+ return dict([(unwrap(x), unwrap(y)) for x, y in item.items()])
+
+ print('Dictionary item not handled')
+ print(type(item))
+ return item
+
+def join_cb():
+ print('Join procedure started')
+
+def join_error_cb(reason):
+ print('Join procedure failed: ', reason)
+
+def attach_app_cb(node_path, dict_array):
+ print('Mesh application registered ', node_path)
+
+ obj = bus.get_object(MESH_SERVICE_NAME, node_path)
+
+ global node
+ node = dbus.Interface(obj, MESH_NODE_IFACE)
+
+ els = unwrap(dict_array)
+ print("Get Elements")
+
+ for el in els:
+ idx = struct.unpack('b', el[0])[0]
+ print('Configuration for Element ', end='')
+ print(idx)
+
+ models = el[1]
+ element = app.get_element(idx)
+ element.set_model_config(models)
+
+def attach_app_error_cb(error):
+ print('Failed to register application: ' + str(error))
+ mainloop.quit()
+
+def attach(token):
+ print('Attach')
+ mesh_net.Attach(app.get_path(), token,
+ reply_handler=attach_app_cb,
+ error_handler=attach_app_error_cb)
+
+def interfaces_removed_cb(object_path, interfaces):
+ if not mesh_net:
+ return
+
+ if object_path == mesh_net[2]:
+ print('Service was removed')
+ mainloop.quit()
+
+def send_response(path, dest, key, data):
+ print('send response ', end='')
+ print(data)
+ node.Send(path, dest, key, data, reply_handler=generic_reply_cb,
+ error_handler=generic_error_cb)
+
+def send_publication(path, model_id, data):
+ print('send publication ', end='')
+ print(data)
+ node.Publish(path, model_id, data, reply_handler=generic_reply_cb,
+ error_handler=generic_error_cb)
+
+class PubTimer():
+ def __init__(self):
+ self.seconds = None
+ self.func = None
+ self.thread = None
+ self.busy = False
+
+ def _timeout_cb(self):
+ self.func()
+ self.busy = True
+ self._schedule_timer()
+ self.busy =False
+
+ def _schedule_timer(self):
+ self.thread = Timer(self.seconds, self._timeout_cb)
+ self.thread.start()
+
+ def start(self, seconds, func):
+ self.func = func
+ self.seconds = seconds
+ if not self.busy:
+ self._schedule_timer()
+
+ def cancel(self):
+ print('Cancel timer')
+ if self.thread is not None:
+ print('Cancel thread')
+ self.thread.cancel()
+ self.thread = None
+
+class Application(dbus.service.Object):
+
+ def __init__(self, bus):
+ self.path = '/example'
+ self.agent = None
+ self.elements = []
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def set_agent(self, agent):
+ self.agent = agent
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+ def add_element(self, element):
+ self.elements.append(element)
+
+ def get_element(self, idx):
+ for ele in self.elements:
+ if ele.get_index() == idx:
+ return ele
+
+ def get_properties(self):
+ return {
+ MESH_APPLICATION_IFACE: {
+ 'CompanyID': dbus.UInt16(APP_COMPANY_ID),
+ 'ProductID': dbus.UInt16(APP_PRODUCT_ID),
+ 'VersionID': dbus.UInt16(APP_VERSION_ID)
+ }
+ }
+
+ @dbus.service.method(DBUS_OM_IFACE, out_signature='a{oa{sa{sv}}}')
+
+ def GetManagedObjects(self):
+ response = {}
+ print('GetManagedObjects')
+ response[self.path] = self.get_properties()
+ response[self.agent.get_path()] = self.agent.get_properties()
+ for element in self.elements:
+ response[element.get_path()] = element.get_properties()
+ return response
+
+ @dbus.service.method(MESH_APPLICATION_IFACE,
+ in_signature="t", out_signature="")
+
+ def JoinComplete(self, value):
+ global token
+ print('JoinComplete ', value)
+
+ token = value
+ attach(token)
+
+ @dbus.service.method(MESH_APPLICATION_IFACE,
+ in_signature="s", out_signature="")
+
+ def JoinFailed(self, value):
+ print('JoinFailed ', value)
+ token = value
+
+class Element(dbus.service.Object):
+ PATH_BASE = '/example/ele'
+
+ def __init__(self, bus, index):
+ self.path = self.PATH_BASE + format(index, '02x')
+ print(self.path)
+ self.models = []
+ self.bus = bus
+ self.index = index
+ dbus.service.Object.__init__(self, bus, self.path)
+
+ def _get_sig_models(self):
+ ids = []
+ for model in self.models:
+ id = model.get_id()
+ vendor = model.get_vendor()
+ if vendor == VENDOR_ID_NONE:
+ ids.append(id)
+ return ids
+
+ def get_properties(self):
+ return {
+ MESH_ELEMENT_IFACE: {
+ 'Index': dbus.Byte(self.index),
+ 'Models': dbus.Array(self._get_sig_models(), 'q')
+ }
+ }
+
+ def add_model(self, model):
+ model.set_path(self.path)
+ self.models.append(model)
+
+ def get_index(self):
+ return self.index
+
+ def set_model_config(self, configs):
+ print('Set element models config')
+ for config in configs:
+ mod_id = config[0]
+ self.UpdateModelConfiguration(mod_id, config[1])
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="qqbay", out_signature="")
+ def MessageReceived(self, source, key, is_sub, data):
+ print('Message Received on Element ', end='')
+ print(self.index)
+ for model in self.models:
+ model.process_message(source, key, data)
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="qa{sv}", out_signature="")
+
+ def UpdateModelConfiguration(self, model_id, config):
+ print('UpdateModelConfig ', end='')
+ print(hex(model_id))
+ for model in self.models:
+ if model_id == model.get_id():
+ model.set_config(config)
+ return
+
+ @dbus.service.method(MESH_ELEMENT_IFACE,
+ in_signature="", out_signature="")
+
+ def get_path(self):
+ return dbus.ObjectPath(self.path)
+
+class Model():
+ def __init__(self, model_id):
+ self.cmd_ops = []
+ self.model_id = model_id
+ self.vendor = VENDOR_ID_NONE
+ self.bindings = []
+ self.pub_period = 0
+ self.pub_id = 0
+ self.path = None
+
+ def set_path(self, path):
+ self.path = path
+
+ def get_id(self):
+ return self.model_id
+
+ def get_vendor(self):
+ return self.vendor
+
+ def process_message(self, source, key, data):
+ print('Model process message')
+
+ def set_publication(self, period):
+ self.pub_period = period
+
+ def set_config(self, config):
+ if 'Bindings' in config:
+ self.bindings = config.get('Bindings')
+ print('Bindings: ', end='')
+ print(self.bindings)
+ if 'PublicationPeriod' in config:
+ self.set_publication(config.get('PublicationPeriod'))
+ print('Model publication period ', end='')
+ print(self.pub_period, end='')
+ print(' ms')
+
+class OnOffServer(Model):
+ def __init__(self, model_id):
+ Model.__init__(self, model_id)
+ self.cmd_ops = { 0x8201, # get
+ 0x8202, # set
+ 0x8203 } # set unacknowledged
+
+ print("OnOff Server ", end="")
+ self.state = 0
+ print('State ', end='')
+ self.timer = PubTimer()
+
+ def process_message(self, source, key, data):
+ datalen = len(data)
+ print('OnOff Server process message len ', datalen)
+
+ if datalen!=2 and datalen!=3:
+ return
+
+ if datalen==2:
+ op_tuple=struct.unpack('<H',bytes(data))
+ opcode = op_tuple[0]
+ if opcode != 0x8201:
+ print(hex(opcode))
+ return
+ print('Get state')
+ elif datalen==3:
+ opcode,self.state=struct.unpack('<HB',bytes(data))
+ if opcode != 0x8202 and opcode != 0x8203:
+ print(hex(opcode))
+ return
+ print('Set state: ', end='')
+ print(self.state)
+
+ rsp_data = struct.pack('<HB', 0x8204, self.state)
+ send_response(self.path, source, key, rsp_data)
+
+ def publish(self):
+ print('Publish')
+ data = struct.pack('B', self.state)
+ send_publication(self.path, self.model_id, data)
+
+ def set_publication(self, period):
+ if period == 0:
+ self.pub_period = 0
+ self.timer.cancel()
+ return
+
+ # We do not handle ms in this example
+ if period < 1000:
+ return
+
+ self.pub_period = period
+ self.timer.start(period/1000, self.publish)
+
+def main():
+
+ DBusGMainLoop(set_as_default=True)
+
+ global bus
+ bus = dbus.SystemBus()
+ global mainloop
+ global app
+ global mesh_net
+
+ mesh_net = dbus.Interface(bus.get_object(MESH_SERVICE_NAME,
+ "/org/bluez/mesh"),
+ MESH_NETWORK_IFACE)
+ mesh_net.connect_to_signal('InterfacesRemoved', interfaces_removed_cb)
+
+ app = Application(bus)
+ prov_agent = agent.Agent(bus)
+ app.set_agent(prov_agent)
+ first_ele = Element(bus, 0x00)
+ first_ele.add_model(OnOffServer(0x1000))
+ app.add_element(first_ele)
+
+ mainloop = GObject.MainLoop()
+
+ print('Join')
+ caps = ["out-numeric"]
+ oob = ["other"]
+ uuid = bytearray.fromhex("0a0102030405060708090A0B0C0D0E0F")
+ print(uuid)
+ mesh_net.Join(app.get_path(), uuid,
+ reply_handler=join_cb,
+ error_handler=join_error_cb)
+
+ mainloop.run()
+
+if __name__ == '__main__':
+ main()
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
* [PATCH BlueZ 30/30] mesh: Enable building Mesh Daemon
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
` (28 preceding siblings ...)
2018-12-14 22:47 ` [PATCH BlueZ 29/30] mesh: Sample Mesh Joiner (provision acceptor) Brian Gix
@ 2018-12-14 22:47 ` Brian Gix
29 siblings, 0 replies; 31+ messages in thread
From: Brian Gix @ 2018-12-14 22:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: johan.hedberg, inga.stotland, marcel, brian.gix
---
Makefile.am | 1 +
1 file changed, 1 insertion(+)
diff --git a/Makefile.am b/Makefile.am
index 7e92977b7..f84a1faba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -303,6 +303,7 @@ unit_tests =
include Makefile.tools
include Makefile.obexd
include android/Makefile.am
+include Makefile.mesh
if HID2HCI
rulesdir = $(UDEV_DIR)/rules.d
--
2.14.5
^ permalink raw reply related [flat|nested] 31+ messages in thread
end of thread, other threads:[~2018-12-14 22:48 UTC | newest]
Thread overview: 31+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-14 22:47 [PATCH BlueZ 00/30] Major rewrite for Multi-Node and DBus Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 01/30] mesh: Staging for Mesh DBus API rewrite Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 02/30] mesh: Delete obsolete files Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 03/30] mesh: Utilities for DBus support Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 04/30] mesh: Internal errors Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 05/30] mesh: Re-write storage for Multiple Nodes Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 06/30] mesh: Rewrite Node handling for multiple nodes Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 07/30] mesh: Rewite Network layer " Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 08/30] mesh: Direction agnostic PB-Adv implimentation Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 09/30] mesh: Acceptor side provisioning implimentation Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 10/30] mesh: Initiator " Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 11/30] mesh: Rewrite Controler interface for full init Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 12/30] mesh: Unchanged variables set to const Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 13/30] mesh: centralize generic utilities Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 14/30] mesh: re-arrange provisioning for DBus API Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 15/30] mesh: Re-architect " Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 16/30] mesh: Make config model handle multiple nodes Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 17/30] mesh: Multi node Config Server model Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 18/30] mesh: restructure I/O for multiple nodes Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 19/30] mesh: Restrusture DB to support " Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 20/30] mesh: restructure model services for " Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 21/30] mesh: DBUS interface for Provisioning Agent Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 22/30] mesh: restructure App Key storage Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 23/30] mesh: Clean-up Comment style Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 24/30] mesh: Update for DBus API and multi-node support Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 25/30] mesh: Add default location for Mesh Node storage Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 26/30] mesh: Add structural changes to for mesh Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 27/30] mesh: Sample Provisioning Agent Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 28/30] mesh: Sample On/Off Client and Server Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 29/30] mesh: Sample Mesh Joiner (provision acceptor) Brian Gix
2018-12-14 22:47 ` [PATCH BlueZ 30/30] mesh: Enable building Mesh Daemon Brian Gix
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).