rel_1.6.0 init

This commit is contained in:
guocheng.kgc 2020-06-18 20:06:52 +08:00 committed by shengdong.dsd
commit 27b3e2883d
19359 changed files with 8093121 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,251 @@
/* att_internal.h - Attribute protocol handling */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define BT_ATT_DEFAULT_LE_MTU 23
#if BT_L2CAP_RX_MTU < CONFIG_BT_L2CAP_TX_MTU
#define BT_ATT_MTU BT_L2CAP_RX_MTU
#else
#define BT_ATT_MTU CONFIG_BT_L2CAP_TX_MTU
#endif
struct bt_att_hdr {
u8_t code;
} __packed;
#define BT_ATT_OP_ERROR_RSP 0x01
struct bt_att_error_rsp {
u8_t request;
u16_t handle;
u8_t error;
} __packed;
#define BT_ATT_OP_MTU_REQ 0x02
struct bt_att_exchange_mtu_req {
u16_t mtu;
} __packed;
#define BT_ATT_OP_MTU_RSP 0x03
struct bt_att_exchange_mtu_rsp {
u16_t mtu;
} __packed;
/* Find Information Request */
#define BT_ATT_OP_FIND_INFO_REQ 0x04
struct bt_att_find_info_req {
u16_t start_handle;
u16_t end_handle;
} __packed;
/* Format field values for BT_ATT_OP_FIND_INFO_RSP */
#define BT_ATT_INFO_16 0x01
#define BT_ATT_INFO_128 0x02
struct bt_att_info_16 {
u16_t handle;
u16_t uuid;
} __packed;
struct bt_att_info_128 {
u16_t handle;
u8_t uuid[16];
} __packed;
/* Find Information Response */
#define BT_ATT_OP_FIND_INFO_RSP 0x05
struct bt_att_find_info_rsp {
u8_t format;
u8_t info[0];
} __packed;
/* Find By Type Value Request */
#define BT_ATT_OP_FIND_TYPE_REQ 0x06
struct bt_att_find_type_req {
u16_t start_handle;
u16_t end_handle;
u16_t type;
u8_t value[0];
} __packed;
struct bt_att_handle_group {
u16_t start_handle;
u16_t end_handle;
} __packed;
/* Find By Type Value Response */
#define BT_ATT_OP_FIND_TYPE_RSP 0x07
struct bt_att_find_type_rsp {
struct bt_att_handle_group list[0];
} __packed;
/* Read By Type Request */
#define BT_ATT_OP_READ_TYPE_REQ 0x08
struct bt_att_read_type_req {
u16_t start_handle;
u16_t end_handle;
u8_t uuid[0];
} __packed;
struct bt_att_data {
u16_t handle;
u8_t value[0];
} __packed;
/* Read By Type Response */
#define BT_ATT_OP_READ_TYPE_RSP 0x09
struct bt_att_read_type_rsp {
u8_t len;
struct bt_att_data data[0];
} __packed;
/* Read Request */
#define BT_ATT_OP_READ_REQ 0x0a
struct bt_att_read_req {
u16_t handle;
} __packed;
/* Read Response */
#define BT_ATT_OP_READ_RSP 0x0b
struct bt_att_read_rsp {
u8_t value[0];
} __packed;
/* Read Blob Request */
#define BT_ATT_OP_READ_BLOB_REQ 0x0c
struct bt_att_read_blob_req {
u16_t handle;
u16_t offset;
} __packed;
/* Read Blob Response */
#define BT_ATT_OP_READ_BLOB_RSP 0x0d
struct bt_att_read_blob_rsp {
u8_t value[0];
} __packed;
/* Read Multiple Request */
#define BT_ATT_READ_MULT_MIN_LEN_REQ 0x04
#define BT_ATT_OP_READ_MULT_REQ 0x0e
struct bt_att_read_mult_req {
u16_t handles[0];
} __packed;
/* Read Multiple Respose */
#define BT_ATT_OP_READ_MULT_RSP 0x0f
struct bt_att_read_mult_rsp {
u8_t value[0];
} __packed;
/* Read by Group Type Request */
#define BT_ATT_OP_READ_GROUP_REQ 0x10
struct bt_att_read_group_req {
u16_t start_handle;
u16_t end_handle;
u8_t uuid[0];
} __packed;
struct bt_att_group_data {
u16_t start_handle;
u16_t end_handle;
u8_t value[0];
} __packed;
/* Read by Group Type Response */
#define BT_ATT_OP_READ_GROUP_RSP 0x11
struct bt_att_read_group_rsp {
u8_t len;
struct bt_att_group_data data[0];
} __packed;
/* Write Request */
#define BT_ATT_OP_WRITE_REQ 0x12
struct bt_att_write_req {
u16_t handle;
u8_t value[0];
} __packed;
/* Write Response */
#define BT_ATT_OP_WRITE_RSP 0x13
/* Prepare Write Request */
#define BT_ATT_OP_PREPARE_WRITE_REQ 0x16
struct bt_att_prepare_write_req {
u16_t handle;
u16_t offset;
u8_t value[0];
} __packed;
/* Prepare Write Respond */
#define BT_ATT_OP_PREPARE_WRITE_RSP 0x17
struct bt_att_prepare_write_rsp {
u16_t handle;
u16_t offset;
u8_t value[0];
} __packed;
/* Execute Write Request */
#define BT_ATT_FLAG_CANCEL 0x00
#define BT_ATT_FLAG_EXEC 0x01
#define BT_ATT_OP_EXEC_WRITE_REQ 0x18
struct bt_att_exec_write_req {
u8_t flags;
} __packed;
/* Execute Write Response */
#define BT_ATT_OP_EXEC_WRITE_RSP 0x19
/* Handle Value Notification */
#define BT_ATT_OP_NOTIFY 0x1b
struct bt_att_notify {
u16_t handle;
u8_t value[0];
} __packed;
/* Handle Value Indication */
#define BT_ATT_OP_INDICATE 0x1d
struct bt_att_indicate {
u16_t handle;
u8_t value[0];
} __packed;
/* Handle Value Confirm */
#define BT_ATT_OP_CONFIRM 0x1e
struct bt_att_signature {
u8_t value[12];
} __packed;
/* Write Command */
#define BT_ATT_OP_WRITE_CMD 0x52
struct bt_att_write_cmd {
u16_t handle;
u8_t value[0];
} __packed;
/* Signed Write Command */
#define BT_ATT_OP_SIGNED_WRITE_CMD 0xd2
struct bt_att_signed_write_cmd {
u16_t handle;
u8_t value[0];
} __packed;
void bt_att_init(void);
u16_t bt_att_get_mtu(struct bt_conn *conn);
struct net_buf *bt_att_create_pdu(struct bt_conn *conn, u8_t op,
size_t len);
/* Send ATT PDU over a connection */
int bt_att_send(struct bt_conn *conn, struct net_buf *buf);
/* Send ATT Request over a connection */
int bt_att_req_send(struct bt_conn *conn, struct bt_att_req *req);
/* Cancel ATT request */
void bt_att_req_cancel(struct bt_conn *conn, struct bt_att_req *req);

View file

@ -0,0 +1,30 @@
zephyr_library()
zephyr_library_link_libraries(subsys__bluetooth)
zephyr_library_sources_ifdef(CONFIG_BT_MESH
main.c
adv.c
beacon.c
net.c
transport.c
crypto.c
access.c
cfg_srv.c
health_srv.c
)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_LOW_POWER lpn.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_FRIEND friend.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROV prov.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROXY proxy.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_CFG_CLI cfg_cli.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_HEALTH_CLI health_cli.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_SELF_TEST test.c)
zephyr_library_sources_ifdef(CONFIG_BT_MESH_SHELL shell.c)

View file

@ -0,0 +1,459 @@
# Kconfig - Bluetooth Mesh configuration options
#
# Copyright (c) 2017 Intel Corporation
#
# SPDX-License-Identifier: Apache-2.0
#
menuconfig BT_MESH
bool "Bluetooth Mesh support"
select TINYCRYPT
select TINYCRYPT_AES
select TINYCRYPT_AES_CMAC
help
This option enables Bluetooth Mesh support. The specific
features that are available may depend on other features
that have been enabled in the stack, such as GATT support.
if BT_MESH
# Virtual option enabled whenever Generic Provisioning layer is needed
config BT_MESH_PROV
bool
config BT_MESH_PB_ADV
bool "Provisioning support using the advertising bearer (PB-ADV)"
select BT_MESH_PROV
default y
help
Enable this option to allow the device to be provisioned over
the advertising bearer.
if BT_CONN
# Virtual option enabled whenever any Proxy protocol is needed
config BT_MESH_PROXY
bool
config BT_MESH_PB_GATT
bool "Provisioning support using GATT (PB-GATT)"
select BT_MESH_PROXY
select BT_MESH_PROV
help
Enable this option to allow the device to be provisioned over
GATT.
config BT_MESH_GATT_PROXY
bool "GATT Proxy Service"
select BT_MESH_PROXY
help
This option enables support for the Mesh GATT Proxy Service,
i.e. the ability to act as a proxy between a Mesh GATT Client
and a Mesh network.
config BT_MESH_NODE_ID_TIMEOUT
int "Node Identity advertising timeout"
depends on BT_MESH_GATT_PROXY
range 1 60
default 60
help
This option determines for how long the local node advertises
using Node Identity. The given value is in seconds. The
specification limits this to 60 seconds, and implies that to
be the appropriate value as well, so just leaving this as the
default is the safest option.
if BT_MESH_PROXY
config BT_MESH_PROXY_FILTER_SIZE
int "Maximum number of filter entries per Proxy Client"
default 1
default 3 if BT_MESH_GATT_PROXY
range 1 32767
help
This option specifies how many Proxy Filter entries the local
node supports.
endif # BT_MESH_PROXY
endif # BT_CONN
config BT_MESH_SELF_TEST
bool "Perform self-tests"
help
This option adds extra self-tests which are run every time
mesh networking is initialized.
config BT_MESH_IV_UPDATE_TEST
bool "Test the IV Update Procedure"
help
This option removes the 96 hour limit of the IV Update
Procedure and lets the state be changed at any time.
config BT_MESH_SUBNET_COUNT
int "Maximum number of mesh subnets per network"
default 1
range 1 4096
help
This option specifies how many subnets a Mesh network can
participate in at the same time.
config BT_MESH_APP_KEY_COUNT
int "Maximum number of application keys per network"
default 1
range 1 4096
help
This option specifies how many application keys the device can
store per network.
config BT_MESH_MODEL_KEY_COUNT
int "Maximum number of application keys per model"
default 1
range 1 4096
help
This option specifies how many application keys each model can
at most be bound to.
config BT_MESH_MODEL_GROUP_COUNT
int "Maximum number of group address subscriptions per model"
default 1
range 1 4096
help
This option specifies how many group addresses each model can
at most be subscribed to.
config BT_MESH_LABEL_COUNT
int "Maximum number of Label UUIDs used for Virtual Addresses"
default 1
range 0 4096
help
This option specifies how many Label UUIDs can be stored.
config BT_MESH_CRPL
int "Maximum capacity of the replay protection list"
default 10
range 2 65535
help
This options specifies the maximum capacity of the replay
protection list. This option is similar to the network message
cache size, but has a different purpose.
config BT_MESH_MSG_CACHE_SIZE
int "Network message cache size"
default 10
range 2 65535
help
Number of messages that are cached for the network. This helps
prevent unnecessary decryption operations and unnecessary
relays. This option is similar to the replay protection list,
but has a different purpose.
config BT_MESH_ADV_BUF_COUNT
int "Number of advertising buffers"
default 6
range 6 256
help
Number of advertising buffers available. The transport layer
reserves ADV_BUF_COUNT - 3 buffers for outgoing segments. The
maximum outgoing SDU size is 12 times this number (out of which
4 or 8 bytes is used for the Transport Layer MIC). For
example, 5 segments means the maximum SDU size is 60 bytes,
which leaves 56 bytes for application layer data using a
4-byte MIC and 52 bytes using an 8-byte MIC.
config BT_MESH_TX_SEG_MSG_COUNT
int "Maximum number of simultaneous outgoing segmented messages"
default 1
range 1 BT_MESH_ADV_BUF_COUNT
help
Maximum number of simultaneous outgoing multi-segment and/or
reliable messages.
config BT_MESH_RX_SEG_MSG_COUNT
int "Maximum number of simultaneous incoming segmented messages"
default 1
range 1 255
help
Maximum number of simultaneous incoming multi-segment and/or
reliable messages.
config BT_MESH_RX_SDU_MAX
int "Maximum incoming Upper Transport Access PDU length"
default 384
range 36 384
help
Maximum incoming Upper Transport Access PDU length. Leave this
to the default value, unless you really need to optimize memory
usage.
config BT_MESH_RELAY
bool "Relay support"
help
Support for acting as a Mesh Relay Node.
config BT_MESH_LOW_POWER
bool "Support for Low Power features"
help
Enable this option to be able to act as a Low Power Node.
if BT_MESH_LOW_POWER
config BT_MESH_LPN_ESTABLISHMENT
bool "Perform Friendship establishment using low power"
default y
help
Perform the Friendship establishment using low power, with
the help of a reduced scan duty cycle. The downside of this
is that the node may miss out on messages intended for it
until it has successfully set up Friendship with a Friend
node.
config BT_MESH_LPN_AUTO
bool "Automatically start looking for Friend nodes once provisioned"
default y
help
Automatically enable LPN functionality once provisioned and start
looking for Friend nodes. If this option is disabled LPN mode
needs to be manually enabled by calling bt_mesh_lpn_set(true).
config BT_MESH_LPN_AUTO_TIMEOUT
int "Time from last received message before going to LPN mode"
default 15
range 0 3600
depends on BT_MESH_LPN_AUTO
help
Time in seconds from the last received message, that the node
will wait before starting to look for Friend nodes.
config BT_MESH_LPN_RETRY_TIMEOUT
int "Retry timeout for Friend requests"
default 8
range 1 3600
help
Time in seconds between Friend Requests, if a previous Friend
Request did not receive any acceptable Friend Offers.
config BT_MESH_LPN_RSSI_FACTOR
int "RSSIFactor, used in the Friend Offer Delay calculation"
range 0 3
default 0
help
The contribution of the RSSI measured by the Friend node used
in Friend Offer Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5.
config BT_MESH_LPN_RECV_WIN_FACTOR
int "ReceiveWindowFactor, used in the Friend Offer Delay calculation"
range 0 3
default 0
help
The contribution of the supported Receive Window used in
Friend Offer Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5.
config BT_MESH_LPN_MIN_QUEUE_SIZE
int "Minimum size of acceptable friend queue (MinQueueSizeLog)"
range 1 7
default 1
help
The MinQueueSizeLog field is defined as log_2(N), where N is
the minimum number of maximum size Lower Transport PDUs that
the Friend node can store in its Friend Queue. As an example,
MinQueueSizeLog value 1 gives N = 2, and value 7 gives N = 128.
config BT_MESH_LPN_RECV_DELAY
int "Receive delay requested by the local node"
range 10 255
default 100
help
The ReceiveDelay is the time between the Low Power node
sending a request and listening for a response. This delay
allows the Friend node time to prepare the response. The value
is in units of milliseconds.
config BT_MESH_LPN_POLL_TIMEOUT
int "The value of the PollTimeout timer"
range 10 244735
default 300
help
PollTimeout timer is used to measure time between two
consecutive requests sent by the Low Power node. If no
requests are received by the Friend node before the
PollTimeout timer expires, then the friendship is considered
terminated. The value is in units of 100 milliseconds, so e.g.
a value of 300 means 3 seconds.
config BT_MESH_LPN_INIT_POLL_TIMEOUT
int "The starting value of the PollTimeout timer"
range 10 BT_MESH_LPN_POLL_TIMEOUT
default BT_MESH_LPN_POLL_TIMEOUT
help
The initial value of the PollTimeout timer when Friendship
gets established for the first time. After this the timeout
will gradually grow toward the actual PollTimeout, doubling
in value for each iteration. The value is in units of 100
milliseconds, so e.g. a value of 300 means 30 seconds.
config BT_MESH_LPN_SCAN_LATENCY
int "Latency for enabling scanning"
range 0 50
default 10
help
Latency in milliseconds that it takes to enable scanning. This
is in practice how much time in advance before the Receive Window
that scanning is requested to be enabled.
config BT_MESH_LPN_GROUPS
int "Number of groups the LPN can subscribe to"
range 0 16384
default 8
help
Maximum number of groups that the LPN can subscribe to.
endif # BT_MESH_LOW_POWER
config BT_MESH_FRIEND
bool "Support for acting as a Friend Node"
help
Enable this option to be able to act as a Friend Node.
if BT_MESH_FRIEND
config BT_MESH_FRIEND_RECV_WIN
int "Friend Receive Window"
range 1 255
default 255
help
Receive Window in milliseconds supported by the Friend node.
config BT_MESH_FRIEND_QUEUE_SIZE
int "Minimum number of buffers supported per Friend Queue"
range 2 65536
default 16
help
Minimum number of buffers available to be stored for each
local Friend Queue.
config BT_MESH_FRIEND_SUB_LIST_SIZE
int "Friend Subscription List Size"
range 0 1023
default 3
help
Size of the Subscription List that can be supported by a
Friend node for a Low Power node.
config BT_MESH_FRIEND_LPN_COUNT
int "Number of supported LPN nodes"
range 1 1000
default 2
help
Number of Low Power Nodes the Friend can have a Friendship
with simultaneously.
config BT_MESH_FRIEND_SEG_RX
int "Number of incomplete segment lists per LPN"
range 1 1000
default 1
help
Number of incomplete segment lists that we track for each LPN
that we are Friends for. In other words, this determines how
many elements we can simultaneously be receiving segmented
messages from when the messages are going into the Friend queue.
endif # BT_MESH_FRIEND
config BT_MESH_CFG_CLI
bool "Support for Configuration Client Model"
help
Enable support for the configuration client model.
config BT_MESH_HEALTH_CLI
bool "Support for Health Client Model"
help
Enable support for the health client model.
config BT_MESH_SHELL
bool "Enable Bluetooth Mesh shell"
select CONSOLE_SHELL
depends on BT_MESH_CFG_CLI
depends on BT_MESH_HEALTH_CLI
help
Activate shell module that provides Bluetooth Mesh commands to
the console.
config BT_MESH_DEBUG
bool "Enable debug logs"
depends on BT_DEBUG
help
Use this option to enable debug logs for the Bluetooth
Mesh functionality.
if BT_MESH_DEBUG
config BT_MESH_DEBUG_NET
bool "Network layer debug"
help
Use this option to enable Network layer debug logs for the
Bluetooth Mesh functionality.
config BT_MESH_DEBUG_TRANS
bool "Transport layer debug"
help
Use this option to enable Transport layer debug logs for the
Bluetooth Mesh functionality.
config BT_MESH_DEBUG_BEACON
bool "Beacon debug"
help
Use this option to enable Beacon-related debug logs for the
Bluetooth Mesh functionality.
config BT_MESH_DEBUG_CRYPTO
bool "Crypto debug"
help
Use this option to enable cryptographic debug logs for the
Bluetooth Mesh functionality.
config BT_MESH_DEBUG_PROV
bool "Provisioning debug"
help
Use this option to enable Provisioning debug logs for the
Bluetooth Mesh functionality.
config BT_MESH_DEBUG_ACCESS
bool "Access layer debug"
help
Use this option to enable Access layer and device composition
related debug logs for Bluetooth Mesh.
config BT_MESH_DEBUG_MODEL
bool "Foundation model debug"
help
Use this option to enable debug logs for the Foundation
Models.
config BT_MESH_DEBUG_ADV
bool "Advertising debug"
help
Use this option to enable advertising debug logs for
the Bluetooth Mesh functionality.
config BT_MESH_DEBUG_LOW_POWER
bool "Low Power debug"
help
Use this option to enable Low Power debug logs for the
Bluetooth Mesh functionality.
config BT_MESH_DEBUG_FRIEND
bool "Friend debug"
help
Use this option to enable Friend debug logs for the
Bluetooth Mesh functionality.
config BT_MESH_DEBUG_PROXY
bool "Proxy debug"
depends on BT_MESH_PROXY
help
Use this option to enable Proxy protocol debug logs.
endif # BT_MESH_DEBUG
endif # BT_MESH

View file

@ -0,0 +1,13 @@
Bluetooth Mesh implementation tasks
===================================
* Persistent storage support
* Configuration & Health Clients (Configuration is partially done)
* Provisioner support
* Any generally useful models from the Model Specification
* Find a way to overlay provisioning memory with network memory
(linker magic?)

View file

@ -0,0 +1,704 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <errno.h>
#include <misc/util.h>
#include <misc/byteorder.h>
#include <net/buf.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_ACCESS)
#include "common/log.h"
#include "mesh.h"
#include "adv.h"
#include "net.h"
#include "lpn.h"
#include "transport.h"
#include "access.h"
#include "foundation.h"
static const struct bt_mesh_comp *dev_comp;
static u16_t dev_primary_addr;
static const struct {
const u16_t id;
int (*const init)(struct bt_mesh_model *model, bool primary);
} model_init[] = {
{ BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_init },
{ BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_init },
#if defined(CONFIG_BT_MESH_CFG_CLI)
{ BT_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_init },
#endif
#if defined(CONFIG_BT_MESH_HEALTH_CLI)
{ BT_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_init },
#endif
};
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem,
bool vnd, bool primary,
void *user_data),
void *user_data)
{
int i, j;
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
for (j = 0; j < elem->model_count; j++) {
struct bt_mesh_model *model = &elem->models[j];
func(model, elem, false, i == 0, user_data);
}
for (j = 0; j < elem->vnd_model_count; j++) {
struct bt_mesh_model *model = &elem->vnd_models[j];
func(model, elem, true, i == 0, user_data);
}
}
}
s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
{
int period;
if (!mod->pub) {
return 0;
}
switch (mod->pub->period >> 6) {
case 0x00:
/* 1 step is 100 ms */
period = K_MSEC((mod->pub->period & BIT_MASK(6)) * 100);
break;
case 0x01:
/* 1 step is 1 second */
period = K_SECONDS(mod->pub->period & BIT_MASK(6));
break;
case 0x02:
/* 1 step is 10 seconds */
period = K_SECONDS((mod->pub->period & BIT_MASK(6)) * 10);
break;
case 0x03:
/* 1 step is 10 minutes */
period = K_MINUTES((mod->pub->period & BIT_MASK(6)) * 10);
break;
default:
CODE_UNREACHABLE;
}
return period >> mod->pub->period_div;
}
static s32_t next_period(struct bt_mesh_model *mod)
{
struct bt_mesh_model_pub *pub = mod->pub;
u32_t elapsed, period;
period = bt_mesh_model_pub_period_get(mod);
if (!period) {
return 0;
}
elapsed = k_uptime_get_32() - pub->period_start;
BT_DBG("Publishing took %ums", elapsed);
if (elapsed > period) {
BT_WARN("Publication sending took longer than the period");
/* Return smallest positive number since 0 means disabled */
return K_MSEC(1);
}
return period - elapsed;
}
static void publish_sent(int err, void *user_data)
{
struct bt_mesh_model *mod = user_data;
s32_t delay;
BT_DBG("err %d", err);
if (mod->pub->count) {
delay = BT_MESH_PUB_TRANSMIT_INT(mod->pub->retransmit);
} else {
delay = next_period(mod);
}
if (delay) {
BT_DBG("Publishing next time in %dms", delay);
k_delayed_work_submit(&mod->pub->timer, delay);
}
}
static const struct bt_mesh_send_cb pub_sent_cb = {
.end = publish_sent,
};
static int publish_retransmit(struct bt_mesh_model *mod)
{
struct net_buf_simple *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_model_pub *pub = mod->pub;
struct bt_mesh_app_key *key;
struct bt_mesh_msg_ctx ctx = {
.addr = pub->addr,
.send_ttl = pub->ttl,
};
struct bt_mesh_net_tx tx = {
.ctx = &ctx,
.src = mod->elem->addr,
.xmit = bt_mesh_net_transmit_get(),
.friend_cred = pub->cred,
};
key = bt_mesh_app_key_find(pub->key);
if (!key) {
return -EADDRNOTAVAIL;
}
tx.sub = bt_mesh_subnet_get(key->net_idx);
ctx.net_idx = key->net_idx;
ctx.app_idx = key->app_idx;
net_buf_simple_init(sdu, 0);
net_buf_simple_add_mem(sdu, pub->msg->data, pub->msg->len);
pub->count--;
return bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod);
}
static void mod_publish(struct k_work *work)
{
struct bt_mesh_model_pub *pub = CONTAINER_OF(work,
struct bt_mesh_model_pub,
timer.work);
s32_t period_ms;
int err;
BT_DBG("");
period_ms = bt_mesh_model_pub_period_get(pub->mod);
BT_DBG("period %u ms", period_ms);
if (pub->count) {
err = publish_retransmit(pub->mod);
if (err) {
BT_ERR("Failed to retransmit (err %d)", err);
pub->count = 0;
/* Continue with normal publication */
if (period_ms) {
k_delayed_work_submit(&pub->timer, period_ms);
}
}
return;
}
if (!period_ms) {
return;
}
__ASSERT_NO_MSG(pub->update != NULL);
pub->period_start = k_uptime_get_32();
err = pub->update(pub->mod);
if (err) {
BT_ERR("Failed to update publication message");
return;
}
err = bt_mesh_model_publish(pub->mod);
if (err) {
BT_ERR("Publishing failed (err %d)", err);
}
if (pub->count) {
/* Retransmissions also control the timer */
k_delayed_work_cancel(&pub->timer);
}
}
static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
bool vnd, bool primary, void *user_data)
{
int i;
mod->elem = elem;
if (mod->pub) {
mod->pub->mod = mod;
k_delayed_work_init(&mod->pub->timer, mod_publish);
}
for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
mod->keys[i] = BT_MESH_KEY_UNUSED;
}
if (vnd) {
return;
}
for (i = 0; i < ARRAY_SIZE(model_init); i++) {
if (model_init[i].id == mod->id) {
model_init[i].init(mod, primary);
}
}
}
int bt_mesh_comp_register(const struct bt_mesh_comp *comp)
{
/* There must be at least one element */
if (!comp->elem_count) {
return -EINVAL;
}
dev_comp = comp;
bt_mesh_model_foreach(mod_init, NULL);
return 0;
}
void bt_mesh_comp_provision(u16_t addr)
{
int i;
dev_primary_addr = addr;
BT_DBG("addr 0x%04x elem_count %zu", addr, dev_comp->elem_count);
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
elem->addr = addr++;
BT_DBG("addr 0x%04x mod_count %u vnd_mod_count %u",
elem->addr, elem->model_count, elem->vnd_model_count);
}
}
void bt_mesh_comp_unprovision(void)
{
BT_DBG("");
dev_primary_addr = BT_MESH_ADDR_UNASSIGNED;
bt_mesh_model_foreach(mod_init, NULL);
}
u16_t bt_mesh_primary_addr(void)
{
return dev_primary_addr;
}
u16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, u16_t addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] == addr) {
return &mod->groups[i];
}
}
return NULL;
}
static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
u16_t group_addr)
{
struct bt_mesh_model *model;
u16_t *match;
int i;
for (i = 0; i < elem->model_count; i++) {
model = &elem->models[i];
match = bt_mesh_model_find_group(model, group_addr);
if (match) {
return model;
}
}
for (i = 0; i < elem->vnd_model_count; i++) {
model = &elem->vnd_models[i];
match = bt_mesh_model_find_group(model, group_addr);
if (match) {
return model;
}
}
return NULL;
}
struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr)
{
int i;
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
if (BT_MESH_ADDR_IS_GROUP(addr) ||
BT_MESH_ADDR_IS_VIRTUAL(addr)) {
if (bt_mesh_elem_find_group(elem, addr)) {
return elem;
}
} else if (elem->addr == addr) {
return elem;
}
}
return NULL;
}
u8_t bt_mesh_elem_count(void)
{
return dev_comp->elem_count;
}
static bool model_has_key(struct bt_mesh_model *mod, u16_t key)
{
int i;
for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
if (mod->keys[i] == key) {
return true;
}
}
return false;
}
static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models,
u8_t model_count,
u16_t app_idx, u32_t opcode,
struct bt_mesh_model **model)
{
u8_t i;
for (i = 0; i < model_count; i++) {
const struct bt_mesh_model_op *op;
*model = &models[i];
if (!model_has_key(*model, app_idx)) {
continue;
}
for (op = (*model)->op; op->func; op++) {
if (op->opcode == opcode) {
return op;
}
}
}
*model = NULL;
return NULL;
}
static int get_opcode(struct net_buf_simple *buf, u32_t *opcode)
{
switch (buf->data[0] >> 6) {
case 0x00:
case 0x01:
if (buf->data[0] == 0x7f) {
BT_ERR("Ignoring RFU OpCode");
return -EINVAL;
}
*opcode = net_buf_simple_pull_u8(buf);
return 0;
case 0x02:
if (buf->len < 2) {
BT_ERR("Too short payload for 2-octet OpCode");
return -EINVAL;
}
*opcode = net_buf_simple_pull_be16(buf);
return 0;
case 0x03:
if (buf->len < 3) {
BT_ERR("Too short payload for 3-octet OpCode");
return -EINVAL;
}
*opcode = net_buf_simple_pull_u8(buf) << 16;
*opcode |= net_buf_simple_pull_le16(buf);
return 0;
}
CODE_UNREACHABLE;
}
bool bt_mesh_fixed_group_match(u16_t addr)
{
/* Check for fixed group addresses */
switch (addr) {
case BT_MESH_ADDR_ALL_NODES:
return true;
case BT_MESH_ADDR_PROXIES:
/* TODO: Proxy not yet supported */
return false;
case BT_MESH_ADDR_FRIENDS:
return (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED);
case BT_MESH_ADDR_RELAYS:
return (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED);
default:
return false;
}
}
void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf)
{
struct bt_mesh_model *models, *model;
const struct bt_mesh_model_op *op;
u32_t opcode;
u8_t count;
int i;
BT_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx,
rx->ctx.addr, rx->dst);
BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len));
if (get_opcode(buf, &opcode) < 0) {
BT_WARN("Unable to decode OpCode");
return;
}
BT_DBG("OpCode 0x%08x", opcode);
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
if (BT_MESH_ADDR_IS_UNICAST(rx->dst)) {
if (elem->addr != rx->dst) {
continue;
}
} else if (BT_MESH_ADDR_IS_GROUP(rx->dst) ||
BT_MESH_ADDR_IS_VIRTUAL(rx->dst)) {
if (!bt_mesh_elem_find_group(elem, rx->dst)) {
continue;
}
} else if (i != 0 || !bt_mesh_fixed_group_match(rx->dst)) {
continue;
}
/* SIG models cannot contain 3-byte (vendor) OpCodes, and
* vendor models cannot contain SIG (1- or 2-byte) OpCodes, so
* we only need to do the lookup in one of the model lists.
*/
if (opcode < 0x10000) {
models = elem->models;
count = elem->model_count;
} else {
models = elem->vnd_models;
count = elem->vnd_model_count;
}
op = find_op(models, count, rx->ctx.app_idx, opcode, &model);
if (op) {
struct net_buf_simple_state state;
if (buf->len < op->min_len) {
BT_ERR("Too short message for OpCode 0x%08x",
opcode);
continue;
}
/* The callback will likely parse the buffer, so
* store the parsing state in case multiple models
* receive the message.
*/
net_buf_simple_save(buf, &state);
op->func(model, &rx->ctx, buf);
net_buf_simple_restore(buf, &state);
} else {
BT_DBG("No OpCode 0x%08x for elem %d", opcode, i);
}
}
}
void bt_mesh_model_msg_init(struct net_buf_simple *msg, u32_t opcode)
{
net_buf_simple_init(msg, 0);
if (opcode < 0x100) {
/* 1-byte OpCode */
net_buf_simple_add_u8(msg, opcode);
return;
}
if (opcode < 0x10000) {
/* 2-byte OpCode */
net_buf_simple_add_be16(msg, opcode);
return;
}
/* 3-byte OpCode */
net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff));
net_buf_simple_add_le16(msg, opcode & 0xffff);
}
static int model_send(struct bt_mesh_model *model,
struct bt_mesh_net_tx *tx, bool implicit_bind,
struct net_buf_simple *msg,
const struct bt_mesh_send_cb *cb, void *cb_data)
{
BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", tx->ctx->net_idx,
tx->ctx->app_idx, tx->ctx->addr);
BT_DBG("len %u: %s", msg->len, bt_hex(msg->data, msg->len));
if (!bt_mesh_is_provisioned()) {
BT_ERR("Local node is not yet provisioned");
return -EAGAIN;
}
if (net_buf_simple_tailroom(msg) < 4) {
BT_ERR("Not enough tailroom for TransMIC");
return -EINVAL;
}
if (msg->len > BT_MESH_TX_SDU_MAX - 4) {
BT_ERR("Too big message");
return -EMSGSIZE;
}
if (!implicit_bind && !model_has_key(model, tx->ctx->app_idx)) {
BT_ERR("Model not bound to AppKey 0x%04x", tx->ctx->app_idx);
return -EINVAL;
}
return bt_mesh_trans_send(tx, msg, cb, cb_data);
}
int bt_mesh_model_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *msg,
const struct bt_mesh_send_cb *cb, void *cb_data)
{
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(ctx->net_idx),
.ctx = ctx,
.src = model->elem->addr,
.xmit = bt_mesh_net_transmit_get(),
.friend_cred = 0,
};
return model_send(model, &tx, false, msg, cb, cb_data);
}
int bt_mesh_model_publish(struct bt_mesh_model *model)
{
struct net_buf_simple *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_model_pub *pub = model->pub;
struct bt_mesh_app_key *key;
struct bt_mesh_msg_ctx ctx = {
};
struct bt_mesh_net_tx tx = {
.ctx = &ctx,
.src = model->elem->addr,
.xmit = bt_mesh_net_transmit_get(),
};
int err;
BT_DBG("");
if (!pub) {
return -ENOTSUP;
}
if (pub->addr == BT_MESH_ADDR_UNASSIGNED) {
return -EADDRNOTAVAIL;
}
key = bt_mesh_app_key_find(pub->key);
if (!key) {
return -EADDRNOTAVAIL;
}
if (pub->msg->len + 4 > BT_MESH_TX_SDU_MAX) {
BT_ERR("Message does not fit maximum SDU size");
return -EMSGSIZE;
}
if (pub->count) {
BT_WARN("Clearing publish retransmit timer");
k_delayed_work_cancel(&pub->timer);
}
net_buf_simple_init(sdu, 0);
net_buf_simple_add_mem(sdu, pub->msg->data, pub->msg->len);
ctx.addr = pub->addr;
ctx.send_ttl = pub->ttl;
ctx.net_idx = key->net_idx;
ctx.app_idx = key->app_idx;
tx.friend_cred = pub->cred;
tx.sub = bt_mesh_subnet_get(ctx.net_idx),
pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit);
BT_DBG("Publish Retransmit Count %u Interval %ums", pub->count,
BT_MESH_PUB_TRANSMIT_INT(pub->retransmit));
err = model_send(model, &tx, true, sdu, &pub_sent_cb, model);
if (err) {
pub->count = 0;
return err;
}
return 0;
}
struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem,
u16_t company, u16_t id)
{
u8_t i;
for (i = 0; i < elem->vnd_model_count; i++) {
if (elem->vnd_models[i].vnd.company == company &&
elem->vnd_models[i].vnd.id == id) {
return &elem->vnd_models[i];
}
}
return NULL;
}
struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem,
u16_t id)
{
u8_t i;
for (i = 0; i < elem->model_count; i++) {
if (elem->models[i].id == id) {
return &elem->models[i];
}
}
return NULL;
}
const struct bt_mesh_comp *bt_mesh_comp_get(void)
{
return dev_comp;
}

View file

@ -0,0 +1,42 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
void bt_mesh_elem_register(struct bt_mesh_elem *elem, u8_t count);
u8_t bt_mesh_elem_count(void);
/* Find local element based on unicast or group address */
struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr);
struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem,
u16_t company, u16_t id);
struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem,
u16_t id);
u16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, u16_t addr);
bool bt_mesh_fixed_group_match(u16_t addr);
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem,
bool vnd, bool primary,
void *user_data),
void *user_data);
s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod);
void bt_mesh_comp_provision(u16_t addr);
void bt_mesh_comp_unprovision(void);
u16_t bt_mesh_primary_addr(void);
const struct bt_mesh_comp *bt_mesh_comp_get(void);
void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf);
int bt_mesh_comp_register(const struct bt_mesh_comp *comp);

View file

@ -0,0 +1,315 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <misc/stack.h>
#include <misc/util.h>
#include <net/buf.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_ADV)
#include "common/log.h"
#include "../hci_core.h"
#include "adv.h"
#include "foundation.h"
#include "net.h"
#include "beacon.h"
#include "prov.h"
#include "proxy.h"
/* Window and Interval are equal for continuous scanning */
#define MESH_SCAN_INTERVAL 0x10
#define MESH_SCAN_WINDOW 0x10
/* Convert from ms to 0.625ms units */
#define ADV_INT(_ms) ((_ms) * 8 / 5)
/* Pre-5.0 controllers enforce a minimum interval of 100ms
* whereas 5.0+ controllers can go down to 20ms.
*/
#define ADV_INT_DEFAULT K_MSEC(100)
#define ADV_INT_FAST K_MSEC(20)
/* TinyCrypt PRNG consumes a lot of stack space, so we need to have
* an increased call stack whenever it's used.
*/
#if defined(CONFIG_BT_HOST_CRYPTO)
#define ADV_STACK_SIZE 768
#else
#define ADV_STACK_SIZE 512
#endif
static K_FIFO_DEFINE(adv_queue);
static struct k_thread adv_thread_data;
static BT_STACK_NOINIT(adv_thread_stack, ADV_STACK_SIZE);
static const u8_t adv_type[] = {
[BT_MESH_ADV_PROV] = BT_DATA_MESH_PROV,
[BT_MESH_ADV_DATA] = BT_DATA_MESH_MESSAGE,
[BT_MESH_ADV_BEACON] = BT_DATA_MESH_BEACON,
};
#if 0
NET_BUF_POOL_DEFINE(adv_buf_pool, CONFIG_BT_MESH_ADV_BUF_COUNT,
BT_MESH_ADV_DATA_SIZE, BT_MESH_ADV_USER_DATA_SIZE, NULL);
#endif
extern struct net_buf_pool adv_buf_pool;
static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT];
static struct bt_mesh_adv *adv_alloc(int id)
{
return &adv_pool[id];
}
static inline void adv_send_start(u16_t duration, int err,
const struct bt_mesh_send_cb *cb,
void *cb_data)
{
if (cb && cb->start) {
cb->start(duration, err, cb_data);
}
}
static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb,
void *cb_data)
{
if (cb && cb->end) {
cb->end(err, cb_data);
}
}
static inline void adv_send(struct net_buf *buf)
{
const s32_t adv_int_min = ((bt_dev.hci_version >= BT_HCI_VERSION_5_0) ?
ADV_INT_FAST : ADV_INT_DEFAULT);
const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
void *cb_data = BT_MESH_ADV(buf)->cb_data;
struct bt_le_adv_param param;
u16_t duration, adv_int;
struct bt_data ad;
int err;
adv_int = max(adv_int_min, BT_MESH_ADV(buf)->adv_int);
duration = (BT_MESH_ADV(buf)->count + 1) * (adv_int + 10);
BT_DBG("type %u len %u: %s", BT_MESH_ADV(buf)->type,
buf->len, bt_hex(buf->data, buf->len));
BT_DBG("count %u interval %ums duration %ums",
BT_MESH_ADV(buf)->count + 1, adv_int, duration);
ad.type = adv_type[BT_MESH_ADV(buf)->type];
ad.data_len = buf->len;
ad.data = buf->data;
param.options = 0;
param.interval_min = ADV_INT(adv_int);
param.interval_max = param.interval_min;
param.own_addr = NULL;
err = bt_le_adv_start(&param, &ad, 1, NULL, 0);
net_buf_unref(buf);
adv_send_start(duration, err, cb, cb_data);
if (err) {
BT_ERR("Advertising failed: err %d", err);
goto exit;
}
BT_DBG("Advertising started. Sleeping %u ms", duration);
k_sleep(duration);
exit:
err = bt_le_adv_stop();
adv_send_end(err, cb, cb_data);
if (err) {
BT_ERR("Stopping advertising failed: err %d", err);
return;
}
BT_DBG("Advertising stopped");
}
static void adv_thread(void *p1, void *p2, void *p3)
{
BT_DBG("started");
while (1) {
struct net_buf *buf;
if (IS_ENABLED(CONFIG_BT_MESH_PROXY)) {
buf = net_buf_get(&adv_queue, K_NO_WAIT);
while (!buf) {
s32_t timeout;
timeout = bt_mesh_proxy_adv_start();
BT_DBG("Proxy Advertising up to %d ms",
timeout);
buf = net_buf_get(&adv_queue, timeout);
bt_mesh_proxy_adv_stop();
}
} else {
buf = net_buf_get(&adv_queue, K_FOREVER);
}
if (!buf) {
continue;
}
/* busy == 0 means this was canceled */
if (BT_MESH_ADV(buf)->busy) {
BT_MESH_ADV(buf)->busy = 0;
adv_send(buf);
}
STACK_ANALYZE("adv stack", adv_thread_stack);
k_call_stacks_analyze();
/* Give other threads a chance to run */
k_yield();
}
}
void bt_mesh_adv_update(void)
{
BT_DBG("");
k_fifo_cancel_wait(&adv_queue);
}
struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool,
bt_mesh_adv_alloc_t get_id,
enum bt_mesh_adv_type type,
u8_t xmit_count, u8_t xmit_int,
s32_t timeout)
{
struct bt_mesh_adv *adv;
struct net_buf *buf;
buf = net_buf_alloc(pool, timeout);
if (!buf) {
return NULL;
}
adv = get_id(net_buf_id(buf));
BT_MESH_ADV(buf) = adv;
memset(adv, 0, sizeof(*adv));
adv->type = type;
adv->count = xmit_count;
adv->adv_int = xmit_int;
return buf;
}
struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit_count,
u8_t xmit_int, s32_t timeout)
{
return bt_mesh_adv_create_from_pool(&adv_buf_pool, adv_alloc, type,
xmit_count, xmit_int, timeout);
}
void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb,
void *cb_data)
{
BT_DBG("type 0x%02x len %u: %s", BT_MESH_ADV(buf)->type, buf->len,
bt_hex(buf->data, buf->len));
BT_MESH_ADV(buf)->cb = cb;
BT_MESH_ADV(buf)->cb_data = cb_data;
BT_MESH_ADV(buf)->busy = 1;
net_buf_put(&adv_queue, net_buf_ref(buf));
}
static void bt_mesh_scan_cb(const bt_addr_le_t *addr, s8_t rssi,
u8_t adv_type, struct net_buf_simple *buf)
{
if (adv_type != BT_LE_ADV_NONCONN_IND) {
return;
}
BT_DBG("len %u: %s", buf->len, bt_hex(buf->data, buf->len));
while (buf->len > 1) {
struct net_buf_simple_state state;
u8_t len, type;
len = net_buf_simple_pull_u8(buf);
/* Check for early termination */
if (len == 0) {
return;
}
if (len > buf->len || buf->len < 1) {
BT_WARN("AD malformed");
return;
}
net_buf_simple_save(buf, &state);
type = net_buf_simple_pull_u8(buf);
buf->len = len - 1;
switch (type) {
case BT_DATA_MESH_MESSAGE:
bt_mesh_net_recv(buf, rssi, BT_MESH_NET_IF_ADV);
break;
#if defined(CONFIG_BT_MESH_PB_ADV)
case BT_DATA_MESH_PROV:
bt_mesh_pb_adv_recv(buf);
break;
#endif
case BT_DATA_MESH_BEACON:
bt_mesh_beacon_recv(buf);
break;
default:
break;
}
net_buf_simple_restore(buf, &state);
net_buf_simple_pull(buf, len);
}
}
void bt_mesh_adv_init(void)
{
k_fifo_init(&adv_queue);
k_lifo_init(&adv_buf_pool.free);
k_thread_create(&adv_thread_data, adv_thread_stack,
K_THREAD_STACK_SIZEOF(adv_thread_stack), adv_thread,
NULL, NULL, NULL, CONFIG_BT_MESH_ADV_PRIO, 0, K_NO_WAIT);
}
int bt_mesh_scan_enable(void)
{
struct bt_le_scan_param scan_param = {
.type = BT_HCI_LE_SCAN_PASSIVE,
.filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE,
.interval = MESH_SCAN_INTERVAL,
.window = MESH_SCAN_WINDOW };
BT_DBG("");
return bt_le_scan_start(&scan_param, bt_mesh_scan_cb);
}
int bt_mesh_scan_disable(void)
{
BT_DBG("");
return bt_le_scan_stop();
}

View file

@ -0,0 +1,66 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/* Maximum advertising data payload for a single data type */
#define BT_MESH_ADV_DATA_SIZE 29
/* The user data is a pointer (4 bytes) to struct bt_mesh_adv */
#define BT_MESH_ADV_USER_DATA_SIZE 4
#define BT_MESH_ADV(buf) (*(struct bt_mesh_adv **)net_buf_user_data(buf))
enum bt_mesh_adv_type {
BT_MESH_ADV_PROV,
BT_MESH_ADV_DATA,
BT_MESH_ADV_BEACON,
};
typedef void (*bt_mesh_adv_func_t)(struct net_buf *buf, u16_t duration,
int err, void *user_data);
struct bt_mesh_adv {
const struct bt_mesh_send_cb *cb;
void *cb_data;
u8_t type:2,
busy:1;
u8_t count:3,
adv_int:5;
union {
/* Address, used e.g. for Friend Queue messages */
u16_t addr;
/* For transport layer segment sending */
struct {
u8_t attempts;
} seg;
};
};
typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id);
/* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */
struct net_buf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit_count,
u8_t xmit_int, s32_t timeout);
struct net_buf *bt_mesh_adv_create_from_pool(struct net_buf_pool *pool,
bt_mesh_adv_alloc_t get_id,
enum bt_mesh_adv_type type,
u8_t xmit_count, u8_t xmit_int,
s32_t timeout);
void bt_mesh_adv_send(struct net_buf *buf, const struct bt_mesh_send_cb *cb,
void *cb_data);
void bt_mesh_adv_update(void);
void bt_mesh_adv_init(void);
int bt_mesh_scan_enable(void);
int bt_mesh_scan_disable(void);

View file

@ -0,0 +1,385 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <errno.h>
#include <misc/util.h>
#include <net/buf.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_BEACON)
#include "common/log.h"
#include "adv.h"
#include "mesh.h"
#include "net.h"
#include "prov.h"
#include "crypto.h"
#include "beacon.h"
#include "foundation.h"
#define UNPROVISIONED_INTERVAL K_SECONDS(5)
#define PROVISIONED_INTERVAL K_SECONDS(10)
#define BEACON_TYPE_UNPROVISIONED 0x00
#define BEACON_TYPE_SECURE 0x01
/* 3 transmissions, 20ms interval */
#define UNPROV_XMIT_COUNT 2
#define UNPROV_XMIT_INT 20
/* 1 transmission, 20ms interval */
#define PROV_XMIT_COUNT 0
#define PROV_XMIT_INT 20
static struct k_delayed_work beacon_timer;
static struct bt_mesh_subnet *cache_check(u8_t data[21])
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (!memcmp(sub->beacon_cache, data, 21)) {
return sub;
}
}
return NULL;
}
static void cache_add(u8_t data[21], struct bt_mesh_subnet *sub)
{
memcpy(sub->beacon_cache, data, 21);
}
static void beacon_complete(int err, void *user_data)
{
struct bt_mesh_subnet *sub = user_data;
BT_DBG("err %d", err);
sub->beacon_sent = k_uptime_get_32();
}
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
struct net_buf_simple *buf)
{
u8_t flags = bt_mesh_net_flags(sub);
struct bt_mesh_subnet_keys *keys;
net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE);
if (sub->kr_flag) {
keys = &sub->keys[1];
} else {
keys = &sub->keys[0];
}
net_buf_simple_add_u8(buf, flags);
/* Network ID */
net_buf_simple_add_mem(buf, keys->net_id, 8);
/* IV Index */
net_buf_simple_add_be32(buf, bt_mesh.iv_index);
net_buf_simple_add_mem(buf, sub->auth, 8);
BT_DBG("net_idx 0x%04x flags 0x%02x NetID %s", sub->net_idx,
flags, bt_hex(keys->net_id, 8));
BT_DBG("IV Index 0x%08x Auth %s", bt_mesh.iv_index,
bt_hex(sub->auth, 8));
}
/* If the interval has passed or is within 5 seconds from now send a beacon */
#define BEACON_THRESHOLD(sub) (K_SECONDS(10 * ((sub)->beacons_last + 1)) - \
K_SECONDS(5))
static int secure_beacon_send(void)
{
static const struct bt_mesh_send_cb send_cb = {
.end = beacon_complete,
};
u32_t now = k_uptime_get_32();
int i;
BT_DBG("");
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
struct net_buf *buf;
u32_t time_diff;
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
time_diff = now - sub->beacon_sent;
if (time_diff < K_SECONDS(600) &&
time_diff < BEACON_THRESHOLD(sub)) {
continue;
}
buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, PROV_XMIT_COUNT,
PROV_XMIT_INT, K_NO_WAIT);
if (!buf) {
BT_ERR("Unable to allocate beacon buffer");
return -ENOBUFS;
}
bt_mesh_beacon_create(sub, &buf->b);
bt_mesh_adv_send(buf, &send_cb, sub);
net_buf_unref(buf);
}
return 0;
}
static int unprovisioned_beacon_send(void)
{
#if defined(CONFIG_BT_MESH_PB_ADV)
struct net_buf *buf;
BT_DBG("");
buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, UNPROV_XMIT_COUNT,
UNPROV_XMIT_INT, K_NO_WAIT);
if (!buf) {
BT_ERR("Unable to allocate beacon buffer");
return -ENOBUFS;
}
net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED);
net_buf_add_mem(buf, bt_mesh_prov_get_uuid(), 16);
/* OOB Info (2 bytes) + URI Hash (4 bytes) */
memset(net_buf_add(buf, 2 + 4), 0, 2 + 4);
bt_mesh_adv_send(buf, NULL, NULL);
net_buf_unref(buf);
#endif /* CONFIG_BT_MESH_PB_ADV */
return 0;
}
static void update_beacon_observation(void)
{
static bool first_half;
int i;
/* Observation period is 20 seconds, whereas the beacon timer
* runs every 10 seconds. We process what's happened during the
* window only after the seconnd half.
*/
first_half = !first_half;
if (first_half) {
return;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
sub->beacons_last = sub->beacons_cur;
sub->beacons_cur = 0;
}
}
static void beacon_send(struct k_work *work)
{
/* Don't send anything if we have an active provisioning link */
if (IS_ENABLED(CONFIG_BT_MESH_PROV) && bt_prov_active()) {
k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL);
return;
}
BT_DBG("");
if (bt_mesh_is_provisioned()) {
update_beacon_observation();
secure_beacon_send();
/* Only resubmit if beaconing is still enabled */
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED ||
bt_mesh.ivu_initiator) {
k_delayed_work_submit(&beacon_timer,
PROVISIONED_INTERVAL);
}
} else {
unprovisioned_beacon_send();
k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL);
}
}
static void secure_beacon_recv(struct net_buf_simple *buf)
{
u8_t *data, *net_id, *auth;
struct bt_mesh_subnet *sub;
u32_t iv_index;
bool new_key, kr_change, iv_change;
u8_t flags;
if (buf->len < 21) {
BT_ERR("Too short secure beacon (len %u)", buf->len);
return;
}
sub = cache_check(buf->data);
if (sub) {
/* We've seen this beacon before - just update the stats */
goto update_stats;
}
/* So we can add to the cache if auth matches */
data = buf->data;
flags = net_buf_simple_pull_u8(buf);
net_id = buf->data;
net_buf_simple_pull(buf, 8);
iv_index = net_buf_simple_pull_be32(buf);
auth = buf->data;
BT_DBG("flags 0x%02x id %s iv_index 0x%08x",
flags, bt_hex(net_id, 8), iv_index);
sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key);
if (!sub) {
BT_DBG("No subnet that matched beacon");
return;
}
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !new_key) {
BT_WARN("Ignoring Phase 2 KR Update secured using old key");
return;
}
cache_add(data, sub);
/* If we have NetKey0 accept initiation only from it */
if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) &&
sub->net_idx != BT_MESH_KEY_PRIMARY) {
BT_WARN("Ignoring secure beacon on non-primary subnet");
goto update_stats;
}
BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x",
sub->net_idx, iv_index, bt_mesh.iv_index);
if (bt_mesh.ivu_initiator &&
bt_mesh.iv_update == BT_MESH_IV_UPDATE(flags)) {
bt_mesh_beacon_ivu_initiator(false);
}
iv_change = bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(flags));
kr_change = bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(flags), new_key);
if (kr_change) {
bt_mesh_net_beacon_update(sub);
}
if (iv_change) {
/* Update all subnets */
bt_mesh_net_sec_update(NULL);
} else if (kr_change) {
/* Key Refresh without IV Update only impacts one subnet */
bt_mesh_net_sec_update(sub);
}
update_stats:
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED &&
sub->beacons_cur < 0xff) {
sub->beacons_cur++;
}
}
void bt_mesh_beacon_recv(struct net_buf_simple *buf)
{
u8_t type;
BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len));
if (buf->len < 1) {
BT_ERR("Too short beacon");
return;
}
type = net_buf_simple_pull_u8(buf);
switch (type) {
case BEACON_TYPE_UNPROVISIONED:
BT_DBG("Ignoring unprovisioned device beacon");
break;
case BEACON_TYPE_SECURE:
secure_beacon_recv(buf);
break;
default:
BT_WARN("Unknown beacon type 0x%02x", type);
break;
}
}
void bt_mesh_beacon_init(void)
{
k_delayed_work_init(&beacon_timer, beacon_send);
}
void bt_mesh_beacon_ivu_initiator(bool enable)
{
bt_mesh.ivu_initiator = enable;
if (enable) {
k_work_submit(&beacon_timer.work);
} else if (bt_mesh_beacon_get() == BT_MESH_BEACON_DISABLED) {
k_delayed_work_cancel(&beacon_timer);
}
}
void bt_mesh_beacon_enable(void)
{
int i;
if (!bt_mesh_is_provisioned()) {
k_work_submit(&beacon_timer.work);
return;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
sub->beacons_last = 0;
sub->beacons_cur = 0;
bt_mesh_net_beacon_update(sub);
}
k_work_submit(&beacon_timer.work);
}
void bt_mesh_beacon_disable(void)
{
if (!bt_mesh.ivu_initiator) {
k_delayed_work_cancel(&beacon_timer);
}
}

View file

@ -0,0 +1,19 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
void bt_mesh_beacon_enable(void);
void bt_mesh_beacon_disable(void);
void bt_mesh_beacon_ivu_initiator(bool enable);
void bt_mesh_beacon_recv(struct net_buf_simple *buf);
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
struct net_buf_simple *buf);
void bt_mesh_beacon_init(void);

View file

@ -0,0 +1,22 @@
NAME := bt_mesh
$(NAME)_TYPE := kernel
GLOBAL_INCLUDES += .
$(NAME)_INCLUDES += ../../common/tinycrypt/include/ \
../../include/bluetooth/mesh/
$(NAME)_COMPONENTS += yloop
$(NAME)_SOURCES := main.c \
adv.c \
beacon.c \
net.c \
transport.c \
crypto.c \
access.c \
cfg_srv.c \
health_srv.c \
cfg_cli.c \
proxy.c \
prov.c

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,875 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <toolchain.h>
#include <zephyr/types.h>
#include <misc/byteorder.h>
#include <misc/util.h>
#include <tinycrypt/constants.h>
#include <tinycrypt/utils.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/cmac_mode.h>
#include <tinycrypt/ccm_mode.h>
#include <bluetooth/mesh.h>
#include <bluetooth/crypto.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_CRYPTO)
#include "common/log.h"
#include "mesh.h"
#include "crypto.h"
#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4)
#define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4)
int bt_mesh_aes_cmac(const u8_t key[16], struct bt_mesh_sg *sg,
size_t sg_len, u8_t mac[16])
{
struct tc_aes_key_sched_struct sched;
struct tc_cmac_struct state;
if (tc_cmac_setup(&state, key, &sched) == TC_CRYPTO_FAIL) {
return -EIO;
}
for (; sg_len; sg_len--, sg++) {
if (tc_cmac_update(&state, sg->data,
sg->len) == TC_CRYPTO_FAIL) {
return -EIO;
}
}
if (tc_cmac_final(mac, &state) == TC_CRYPTO_FAIL) {
return -EIO;
}
return 0;
}
int bt_mesh_k1(const u8_t *ikm, size_t ikm_len, const u8_t salt[16],
const char *info, u8_t okm[16])
{
int err;
err = bt_mesh_aes_cmac_one(salt, ikm, ikm_len, okm);
if (err < 0) {
return err;
}
return bt_mesh_aes_cmac_one(okm, info, strlen(info), okm);
}
int bt_mesh_k2(const u8_t n[16], const u8_t *p, size_t p_len,
u8_t net_id[1], u8_t enc_key[16], u8_t priv_key[16])
{
struct bt_mesh_sg sg[3];
u8_t salt[16];
u8_t out[16];
u8_t t[16];
u8_t pad;
int err;
BT_DBG("n %s", bt_hex(n, 16));
BT_DBG("p %s", bt_hex(p, p_len));
err = bt_mesh_s1("smk2", salt);
if (err) {
return err;
}
err = bt_mesh_aes_cmac_one(salt, n, 16, t);
if (err) {
return err;
}
pad = 0x01;
sg[0].data = NULL;
sg[0].len = 0;
sg[1].data = p;
sg[1].len = p_len;
sg[2].data = &pad;
sg[2].len = sizeof(pad);
err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out);
if (err) {
return err;
}
net_id[0] = out[15] & 0x7f;
sg[0].data = out;
sg[0].len = sizeof(out);
pad = 0x02;
err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out);
if (err) {
return err;
}
memcpy(enc_key, out, 16);
pad = 0x03;
err = bt_mesh_aes_cmac(t, sg, ARRAY_SIZE(sg), out);
if (err) {
return err;
}
memcpy(priv_key, out, 16);
BT_DBG("NID 0x%02x enc_key %s", net_id[0], bt_hex(enc_key, 16));
BT_DBG("priv_key %s", bt_hex(priv_key, 16));
return 0;
}
int bt_mesh_k3(const u8_t n[16], u8_t out[8])
{
u8_t id64[] = { 'i', 'd', '6', '4', 0x01 };
u8_t tmp[16];
u8_t t[16];
int err;
err = bt_mesh_s1("smk3", tmp);
if (err) {
return err;
}
err = bt_mesh_aes_cmac_one(tmp, n, 16, t);
if (err) {
return err;
}
err = bt_mesh_aes_cmac_one(t, id64, sizeof(id64), tmp);
if (err) {
return err;
}
memcpy(out, tmp + 8, 8);
return 0;
}
int bt_mesh_k4(const u8_t n[16], u8_t out[1])
{
u8_t id6[] = { 'i', 'd', '6', 0x01 };
u8_t tmp[16];
u8_t t[16];
int err;
err = bt_mesh_s1("smk4", tmp);
if (err) {
return err;
}
err = bt_mesh_aes_cmac_one(tmp, n, 16, t);
if (err) {
return err;
}
err = bt_mesh_aes_cmac_one(t, id6, sizeof(id6), tmp);
if (err) {
return err;
}
out[0] = tmp[15] & BIT_MASK(6);
return 0;
}
int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16])
{
const char *id128 = "id128\x01";
u8_t salt[16];
int err;
err = bt_mesh_s1(s, salt);
if (err) {
return err;
}
return bt_mesh_k1(n, 16, salt, id128, out);
}
static int bt_mesh_ccm_decrypt(const u8_t key[16], u8_t nonce[13],
const u8_t *enc_msg, size_t msg_len,
const u8_t *aad, size_t aad_len,
u8_t *out_msg, size_t mic_size)
{
u8_t msg[16], pmsg[16], cmic[16], cmsg[16], Xn[16], mic[16];
u16_t last_blk, blk_cnt;
size_t i, j;
int err;
if (msg_len < 1 || aad_len >= 0xff00) {
return -EINVAL;
}
/* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
pmsg[0] = 0x01;
memcpy(pmsg + 1, nonce, 13);
sys_put_be16(0x0000, pmsg + 14);
err = bt_encrypt_be(key, pmsg, cmic);
if (err) {
return err;
}
/* X_0 = e(AppKey, 0x09 || nonce || length) */
if (mic_size == sizeof(u64_t)) {
pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
} else {
pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
}
memcpy(pmsg + 1, nonce, 13);
sys_put_be16(msg_len, pmsg + 14);
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
/* If AAD is being used to authenticate, include it here */
if (aad_len) {
sys_put_be16(aad_len, pmsg);
for (i = 0; i < sizeof(u16_t); i++) {
pmsg[i] = Xn[i] ^ pmsg[i];
}
j = 0;
aad_len += sizeof(u16_t);
while (aad_len > 16) {
do {
pmsg[i] = Xn[i] ^ aad[j];
i++, j++;
} while (i < 16);
aad_len -= 16;
i = 0;
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
}
for (i = 0; i < aad_len; i++, j++) {
pmsg[i] = Xn[i] ^ aad[j];
}
for (i = aad_len; i < 16; i++) {
pmsg[i] = Xn[i];
}
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
}
last_blk = msg_len % 16;
blk_cnt = (msg_len + 15) / 16;
if (!last_blk) {
last_blk = 16;
}
for (j = 0; j < blk_cnt; j++) {
if (j + 1 == blk_cnt) {
/* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
pmsg[0] = 0x01;
memcpy(pmsg + 1, nonce, 13);
sys_put_be16(j + 1, pmsg + 14);
err = bt_encrypt_be(key, pmsg, cmsg);
if (err) {
return err;
}
/* Encrypted = Payload[0-15] ^ C_1 */
for (i = 0; i < last_blk; i++) {
msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
}
memcpy(out_msg + (j * 16), msg, last_blk);
/* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
for (i = 0; i < last_blk; i++) {
pmsg[i] = Xn[i] ^ msg[i];
}
for (i = last_blk; i < 16; i++) {
pmsg[i] = Xn[i] ^ 0x00;
}
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
/* MIC = C_mic ^ X_1 */
for (i = 0; i < sizeof(mic); i++) {
mic[i] = cmic[i] ^ Xn[i];
}
} else {
/* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
pmsg[0] = 0x01;
memcpy(pmsg + 1, nonce, 13);
sys_put_be16(j + 1, pmsg + 14);
err = bt_encrypt_be(key, pmsg, cmsg);
if (err) {
return err;
}
/* Encrypted = Payload[0-15] ^ C_1 */
for (i = 0; i < 16; i++) {
msg[i] = enc_msg[(j * 16) + i] ^ cmsg[i];
}
memcpy(out_msg + (j * 16), msg, 16);
/* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
for (i = 0; i < 16; i++) {
pmsg[i] = Xn[i] ^ msg[i];
}
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
}
}
if (memcmp(mic, enc_msg + msg_len, mic_size)) {
return -EBADMSG;
}
return 0;
}
static int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13],
const u8_t *msg, size_t msg_len,
const u8_t *aad, size_t aad_len,
u8_t *out_msg, size_t mic_size)
{
u8_t pmsg[16], cmic[16], cmsg[16], mic[16], Xn[16];
u16_t blk_cnt, last_blk;
size_t i, j;
int err;
BT_DBG("key %s", bt_hex(key, 16));
BT_DBG("nonce %s", bt_hex(nonce, 13));
BT_DBG("msg (len %zu) %s", msg_len, bt_hex(msg, msg_len));
BT_DBG("aad_len %zu mic_size %zu", aad_len, mic_size);
/* Unsupported AAD size */
if (aad_len >= 0xff00) {
return -EINVAL;
}
/* C_mic = e(AppKey, 0x01 || nonce || 0x0000) */
pmsg[0] = 0x01;
memcpy(pmsg + 1, nonce, 13);
sys_put_be16(0x0000, pmsg + 14);
err = bt_encrypt_be(key, pmsg, cmic);
if (err) {
return err;
}
/* X_0 = e(AppKey, 0x09 || nonce || length) */
if (mic_size == sizeof(u64_t)) {
pmsg[0] = 0x19 | (aad_len ? 0x40 : 0x00);
} else {
pmsg[0] = 0x09 | (aad_len ? 0x40 : 0x00);
}
memcpy(pmsg + 1, nonce, 13);
sys_put_be16(msg_len, pmsg + 14);
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
/* If AAD is being used to authenticate, include it here */
if (aad_len) {
sys_put_be16(aad_len, pmsg);
for (i = 0; i < sizeof(u16_t); i++) {
pmsg[i] = Xn[i] ^ pmsg[i];
}
j = 0;
aad_len += sizeof(u16_t);
while (aad_len > 16) {
do {
pmsg[i] = Xn[i] ^ aad[j];
i++, j++;
} while (i < 16);
aad_len -= 16;
i = 0;
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
}
for (i = 0; i < aad_len; i++, j++) {
pmsg[i] = Xn[i] ^ aad[j];
}
for (i = aad_len; i < 16; i++) {
pmsg[i] = Xn[i];
}
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
}
last_blk = msg_len % 16;
blk_cnt = (msg_len + 15) / 16;
if (!last_blk) {
last_blk = 16;
}
for (j = 0; j < blk_cnt; j++) {
if (j + 1 == blk_cnt) {
/* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
for (i = 0; i < last_blk; i++) {
pmsg[i] = Xn[i] ^ msg[(j * 16) + i];
}
for (i = last_blk; i < 16; i++) {
pmsg[i] = Xn[i] ^ 0x00;
}
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
/* MIC = C_mic ^ X_1 */
for (i = 0; i < sizeof(mic); i++) {
mic[i] = cmic[i] ^ Xn[i];
}
/* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
pmsg[0] = 0x01;
memcpy(pmsg + 1, nonce, 13);
sys_put_be16(j + 1, pmsg + 14);
err = bt_encrypt_be(key, pmsg, cmsg);
if (err) {
return err;
}
/* Encrypted = Payload[0-15] ^ C_1 */
for (i = 0; i < last_blk; i++) {
out_msg[(j * 16) + i] =
msg[(j * 16) + i] ^ cmsg[i];
}
} else {
/* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
for (i = 0; i < 16; i++) {
pmsg[i] = Xn[i] ^ msg[(j * 16) + i];
}
err = bt_encrypt_be(key, pmsg, Xn);
if (err) {
return err;
}
/* C_1 = e(AppKey, 0x01 || nonce || 0x0001) */
pmsg[0] = 0x01;
memcpy(pmsg + 1, nonce, 13);
sys_put_be16(j + 1, pmsg + 14);
err = bt_encrypt_be(key, pmsg, cmsg);
if (err) {
return err;
}
/* Encrypted = Payload[0-15] ^ C_N */
for (i = 0; i < 16; i++) {
out_msg[(j * 16) + i] =
msg[(j * 16) + i] ^ cmsg[i];
}
}
}
memcpy(out_msg + msg_len, mic, mic_size);
return 0;
}
#if defined(CONFIG_BT_MESH_PROXY)
static void create_proxy_nonce(u8_t nonce[13], const u8_t *pdu,
u32_t iv_index)
{
/* Nonce Type */
nonce[0] = 0x03;
/* Pad */
nonce[1] = 0x00;
/* Sequence Number */
nonce[2] = pdu[2];
nonce[3] = pdu[3];
nonce[4] = pdu[4];
/* Source Address */
nonce[5] = pdu[5];
nonce[6] = pdu[6];
/* Pad */
nonce[7] = 0;
nonce[8] = 0;
/* IV Index */
sys_put_be32(iv_index, &nonce[9]);
}
#endif /* PROXY */
static void create_net_nonce(u8_t nonce[13], const u8_t *pdu,
u32_t iv_index)
{
/* Nonce Type */
nonce[0] = 0x00;
/* FRND + TTL */
nonce[1] = pdu[1];
/* Sequence Number */
nonce[2] = pdu[2];
nonce[3] = pdu[3];
nonce[4] = pdu[4];
/* Source Address */
nonce[5] = pdu[5];
nonce[6] = pdu[6];
/* Pad */
nonce[7] = 0;
nonce[8] = 0;
/* IV Index */
sys_put_be32(iv_index, &nonce[9]);
}
int bt_mesh_net_obfuscate(u8_t *pdu, u32_t iv_index,
const u8_t privacy_key[16])
{
u8_t priv_rand[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
u8_t tmp[16];
int err, i;
BT_DBG("IVIndex %u, PrivacyKey %s", iv_index, bt_hex(privacy_key, 16));
sys_put_be32(iv_index, &priv_rand[5]);
memcpy(&priv_rand[9], &pdu[7], 7);
BT_DBG("PrivacyRandom %s", bt_hex(priv_rand, 16));
err = bt_encrypt_be(privacy_key, priv_rand, tmp);
if (err) {
return err;
}
for (i = 0; i < 6; i++) {
pdu[1 + i] ^= tmp[i];
}
return 0;
}
int bt_mesh_net_encrypt(const u8_t key[16], struct net_buf_simple *buf,
u32_t iv_index, bool proxy)
{
u8_t mic_len = NET_MIC_LEN(buf->data);
u8_t nonce[13];
int err;
BT_DBG("IVIndex %u EncKey %s mic_len %u", iv_index, bt_hex(key, 16),
mic_len);
BT_DBG("PDU (len %u) %s", buf->len, bt_hex(buf->data, buf->len));
#if defined(CONFIG_BT_MESH_PROXY)
if (proxy) {
create_proxy_nonce(nonce, buf->data, iv_index);
} else {
create_net_nonce(nonce, buf->data, iv_index);
}
#else
create_net_nonce(nonce, buf->data, iv_index);
#endif
BT_DBG("Nonce %s", bt_hex(nonce, 13));
err = bt_mesh_ccm_encrypt(key, nonce, &buf->data[7], buf->len - 7,
NULL, 0, &buf->data[7], mic_len);
if (!err) {
net_buf_simple_add(buf, mic_len);
}
return err;
}
int bt_mesh_net_decrypt(const u8_t key[16], struct net_buf_simple *buf,
u32_t iv_index, bool proxy)
{
u8_t mic_len = NET_MIC_LEN(buf->data);
u8_t nonce[13];
BT_DBG("PDU (%u bytes) %s", buf->len, bt_hex(buf->data, buf->len));
BT_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, 16),
mic_len);
#if defined(CONFIG_BT_MESH_PROXY)
if (proxy) {
create_proxy_nonce(nonce, buf->data, iv_index);
} else {
create_net_nonce(nonce, buf->data, iv_index);
}
#else
create_net_nonce(nonce, buf->data, iv_index);
#endif
BT_DBG("Nonce %s", bt_hex(nonce, 13));
buf->len -= mic_len;
return bt_mesh_ccm_decrypt(key, nonce, &buf->data[7], buf->len - 7,
NULL, 0, &buf->data[7], mic_len);
}
static void create_app_nonce(u8_t nonce[13], bool dev_key, u8_t aszmic,
u16_t src, u16_t dst, u32_t seq_num,
u32_t iv_index)
{
if (dev_key) {
nonce[0] = 0x02;
} else {
nonce[0] = 0x01;
}
sys_put_be32((seq_num | ((u32_t)aszmic << 31)), &nonce[1]);
sys_put_be16(src, &nonce[5]);
sys_put_be16(dst, &nonce[7]);
sys_put_be32(iv_index, &nonce[9]);
}
int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct net_buf_simple *buf, const u8_t *ad,
u16_t src, u16_t dst, u32_t seq_num, u32_t iv_index)
{
u8_t nonce[13];
int err;
BT_DBG("AppKey %s", bt_hex(key, 16));
BT_DBG("dev_key %u src 0x%04x dst 0x%04x", dev_key, src, dst);
BT_DBG("seq_num 0x%08x iv_index 0x%08x", seq_num, iv_index);
BT_DBG("Clear: %s", bt_hex(buf->data, buf->len));
create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index);
BT_DBG("Nonce %s", bt_hex(nonce, 13));
err = bt_mesh_ccm_encrypt(key, nonce, buf->data, buf->len, ad,
ad ? 16 : 0, buf->data, APP_MIC_LEN(aszmic));
if (!err) {
net_buf_simple_add(buf, APP_MIC_LEN(aszmic));
BT_DBG("Encr: %s", bt_hex(buf->data, buf->len));
}
return err;
}
int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct net_buf_simple *buf, struct net_buf_simple *out,
const u8_t *ad, u16_t src, u16_t dst, u32_t seq_num,
u32_t iv_index)
{
u8_t nonce[13];
int err;
BT_DBG("EncData (len %u) %s", buf->len, bt_hex(buf->data, buf->len));
create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index);
BT_DBG("AppKey %s", bt_hex(key, 16));
BT_DBG("Nonce %s", bt_hex(nonce, 13));
err = bt_mesh_ccm_decrypt(key, nonce, buf->data, buf->len, ad,
ad ? 16 : 0, out->data, APP_MIC_LEN(aszmic));
if (!err) {
net_buf_simple_add(out, buf->len);
}
return err;
}
/* reversed, 8-bit, poly=0x07 */
static const u8_t crc_table[256] = {
0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75,
0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b,
0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69,
0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67,
0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d,
0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43,
0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51,
0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f,
0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05,
0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b,
0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19,
0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17,
0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d,
0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33,
0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21,
0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f,
0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95,
0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b,
0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89,
0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87,
0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad,
0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3,
0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1,
0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf,
0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5,
0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb,
0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9,
0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7,
0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd,
0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3,
0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1,
0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
};
u8_t bt_mesh_fcs_calc(const u8_t *data, u8_t data_len)
{
u8_t fcs = 0xff;
while (data_len--) {
fcs = crc_table[fcs ^ *data++];
}
BT_DBG("fcs 0x%02x", 0xff - fcs);
return 0xff - fcs;
}
bool bt_mesh_fcs_check(struct net_buf_simple *buf, u8_t received_fcs)
{
const u8_t *data = buf->data;
u16_t data_len = buf->len;
u8_t fcs = 0xff;
while (data_len--) {
fcs = crc_table[fcs ^ *data++];
}
return crc_table[fcs ^ received_fcs] == 0xcf;
}
int bt_mesh_virtual_addr(const u8_t virtual_label[16], u16_t *addr)
{
u8_t salt[16];
u8_t tmp[16];
int err;
err = bt_mesh_s1("vtad", salt);
if (err) {
return err;
}
err = bt_mesh_aes_cmac_one(salt, virtual_label, 16, tmp);
if (err) {
return err;
}
*addr = (sys_get_be16(&tmp[14]) & 0x3fff) | 0x8000;
return 0;
}
int bt_mesh_prov_conf_salt(const u8_t conf_inputs[145], u8_t salt[16])
{
const u8_t conf_salt_key[16] = { 0 };
return bt_mesh_aes_cmac_one(conf_salt_key, conf_inputs, 145, salt);
}
int bt_mesh_prov_conf_key(const u8_t dhkey[32], const u8_t conf_salt[16],
u8_t conf_key[16])
{
return bt_mesh_k1(dhkey, 32, conf_salt, "prck", conf_key);
}
int bt_mesh_prov_conf(const u8_t conf_key[16], const u8_t rand[16],
const u8_t auth[16], u8_t conf[16])
{
struct bt_mesh_sg sg[] = { { rand, 16 }, { auth, 16 } };
BT_DBG("ConfirmationKey %s", bt_hex(conf_key, 16));
BT_DBG("RandomDevice %s", bt_hex(rand, 16));
BT_DBG("AuthValue %s", bt_hex(auth, 16));
return bt_mesh_aes_cmac(conf_key, sg, ARRAY_SIZE(sg), conf);
}
int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13],
const u8_t data[25 + 8], u8_t out[25])
{
return bt_mesh_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8);
}
int bt_mesh_beacon_auth(const u8_t beacon_key[16], u8_t flags,
const u8_t net_id[8], u32_t iv_index,
u8_t auth[8])
{
u8_t msg[13], tmp[16];
int err;
BT_DBG("BeaconKey %s", bt_hex(beacon_key, 16));
BT_DBG("NetId %s", bt_hex(net_id, 8));
BT_DBG("IV Index 0x%08x", iv_index);
msg[0] = flags;
memcpy(&msg[1], net_id, 8);
sys_put_be32(iv_index, &msg[9]);
BT_DBG("BeaconMsg %s", bt_hex(msg, sizeof(msg)));
err = bt_mesh_aes_cmac_one(beacon_key, msg, sizeof(msg), tmp);
if (!err) {
memcpy(auth, tmp, 8);
}
return err;
}

View file

@ -0,0 +1,154 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
struct bt_mesh_sg {
const void *data;
size_t len;
};
int bt_mesh_aes_cmac(const u8_t key[16], struct bt_mesh_sg *sg,
size_t sg_len, u8_t mac[16]);
static inline int bt_mesh_aes_cmac_one(const u8_t key[16], const void *m,
size_t len, u8_t mac[16])
{
struct bt_mesh_sg sg = { m, len };
return bt_mesh_aes_cmac(key, &sg, 1, mac);
}
static inline bool bt_mesh_s1(const char *m, u8_t salt[16])
{
const u8_t zero[16] = { 0 };
return bt_mesh_aes_cmac_one(zero, m, strlen(m), salt);
}
int bt_mesh_k1(const u8_t *ikm, size_t ikm_len, const u8_t salt[16],
const char *info, u8_t okm[16]);
#define bt_mesh_k1_str(ikm, ikm_len, salt_str, info, okm) \
({ \
const u8_t salt[16] = salt_str; \
bt_mesh_k1(ikm, ikm_len, salt, info, okm); \
})
int bt_mesh_k2(const u8_t n[16], const u8_t *p, size_t p_len,
u8_t net_id[1], u8_t enc_key[16], u8_t priv_key[16]);
int bt_mesh_k3(const u8_t n[16], u8_t out[8]);
int bt_mesh_k4(const u8_t n[16], u8_t out[1]);
int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16]);
static inline int bt_mesh_id_resolving_key(const u8_t net_key[16],
u8_t resolving_key[16])
{
return bt_mesh_k1_str(net_key, 16, "smbt", "smbi", resolving_key);
}
static inline int bt_mesh_identity_key(const u8_t net_key[16],
u8_t identity_key[16])
{
return bt_mesh_id128(net_key, "nkik", identity_key);
}
static inline int bt_mesh_beacon_key(const u8_t net_key[16],
u8_t beacon_key[16])
{
return bt_mesh_id128(net_key, "nkbk", beacon_key);
}
int bt_mesh_beacon_auth(const u8_t beacon_key[16], u8_t flags,
const u8_t net_id[16], u32_t iv_index,
u8_t auth[8]);
static inline int bt_mesh_app_id(const u8_t app_key[16], u8_t app_id[1])
{
return bt_mesh_k4(app_key, app_id);
}
static inline int bt_mesh_session_key(const u8_t dhkey[32],
const u8_t prov_salt[16],
u8_t session_key[16])
{
return bt_mesh_k1(dhkey, 32, prov_salt, "prsk", session_key);
}
static inline int bt_mesh_prov_nonce(const u8_t dhkey[32],
const u8_t prov_salt[16],
u8_t nonce[13])
{
u8_t tmp[16];
int err;
err = bt_mesh_k1(dhkey, 32, prov_salt, "prsn", tmp);
if (!err) {
memcpy(nonce, tmp + 3, 13);
}
return err;
}
static inline int bt_mesh_dev_key(const u8_t dhkey[32],
const u8_t prov_salt[16],
u8_t dev_key[16])
{
return bt_mesh_k1(dhkey, 32, prov_salt, "prdk", dev_key);
}
static inline int bt_mesh_prov_salt(const u8_t conf_salt[16],
const u8_t prov_rand[16],
const u8_t dev_rand[16],
u8_t prov_salt[16])
{
const u8_t prov_salt_key[16] = { 0 };
struct bt_mesh_sg sg[] = {
{ conf_salt, 16 },
{ prov_rand, 16 },
{ dev_rand, 16 },
};
return bt_mesh_aes_cmac(prov_salt_key, sg, ARRAY_SIZE(sg), prov_salt);
}
int bt_mesh_net_obfuscate(u8_t *pdu, u32_t iv_index,
const u8_t privacy_key[16]);
int bt_mesh_net_encrypt(const u8_t key[16], struct net_buf_simple *buf,
u32_t iv_index, bool proxy);
int bt_mesh_net_decrypt(const u8_t key[16], struct net_buf_simple *buf,
u32_t iv_index, bool proxy);
int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct net_buf_simple *buf, const u8_t *ad,
u16_t src, u16_t dst, u32_t seq_num, u32_t iv_index);
int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct net_buf_simple *buf, struct net_buf_simple *out,
const u8_t *ad, u16_t src, u16_t dst, u32_t seq_num,
u32_t iv_index);
u8_t bt_mesh_fcs_calc(const u8_t *data, u8_t data_len);
bool bt_mesh_fcs_check(struct net_buf_simple *buf, u8_t received_fcs);
int bt_mesh_virtual_addr(const u8_t virtual_label[16], u16_t *addr);
int bt_mesh_prov_conf_salt(const u8_t conf_inputs[145], u8_t salt[16]);
int bt_mesh_prov_conf_key(const u8_t dhkey[32], const u8_t conf_salt[16],
u8_t conf_key[16]);
int bt_mesh_prov_conf(const u8_t conf_key[16], const u8_t rand[16],
const u8_t auth[16], u8_t conf[16]);
int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13],
const u8_t data[25 + 8], u8_t out[25]);

View file

@ -0,0 +1,152 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define OP_APP_KEY_ADD BT_MESH_MODEL_OP_1(0x00)
#define OP_APP_KEY_UPDATE BT_MESH_MODEL_OP_1(0x01)
#define OP_DEV_COMP_DATA_STATUS BT_MESH_MODEL_OP_1(0x02)
#define OP_MOD_PUB_SET BT_MESH_MODEL_OP_1(0x03)
#define OP_HEALTH_CURRENT_STATUS BT_MESH_MODEL_OP_1(0x04)
#define OP_HEALTH_FAULT_STATUS BT_MESH_MODEL_OP_1(0x05)
#define OP_HEARTBEAT_PUB_STATUS BT_MESH_MODEL_OP_1(0x06)
#define OP_APP_KEY_DEL BT_MESH_MODEL_OP_2(0x80, 0x00)
#define OP_APP_KEY_GET BT_MESH_MODEL_OP_2(0x80, 0x01)
#define OP_APP_KEY_LIST BT_MESH_MODEL_OP_2(0x80, 0x02)
#define OP_APP_KEY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x03)
#define OP_ATTENTION_GET BT_MESH_MODEL_OP_2(0x80, 0x04)
#define OP_ATTENTION_SET BT_MESH_MODEL_OP_2(0x80, 0x05)
#define OP_ATTENTION_SET_UNREL BT_MESH_MODEL_OP_2(0x80, 0x06)
#define OP_ATTENTION_STATUS BT_MESH_MODEL_OP_2(0x80, 0x07)
#define OP_DEV_COMP_DATA_GET BT_MESH_MODEL_OP_2(0x80, 0x08)
#define OP_BEACON_GET BT_MESH_MODEL_OP_2(0x80, 0x09)
#define OP_BEACON_SET BT_MESH_MODEL_OP_2(0x80, 0x0a)
#define OP_BEACON_STATUS BT_MESH_MODEL_OP_2(0x80, 0x0b)
#define OP_DEFAULT_TTL_GET BT_MESH_MODEL_OP_2(0x80, 0x0c)
#define OP_DEFAULT_TTL_SET BT_MESH_MODEL_OP_2(0x80, 0x0d)
#define OP_DEFAULT_TTL_STATUS BT_MESH_MODEL_OP_2(0x80, 0x0e)
#define OP_FRIEND_GET BT_MESH_MODEL_OP_2(0x80, 0x0f)
#define OP_FRIEND_SET BT_MESH_MODEL_OP_2(0x80, 0x10)
#define OP_FRIEND_STATUS BT_MESH_MODEL_OP_2(0x80, 0x11)
#define OP_GATT_PROXY_GET BT_MESH_MODEL_OP_2(0x80, 0x12)
#define OP_GATT_PROXY_SET BT_MESH_MODEL_OP_2(0x80, 0x13)
#define OP_GATT_PROXY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x14)
#define OP_KRP_GET BT_MESH_MODEL_OP_2(0x80, 0x15)
#define OP_KRP_SET BT_MESH_MODEL_OP_2(0x80, 0x16)
#define OP_KRP_STATUS BT_MESH_MODEL_OP_2(0x80, 0x17)
#define OP_MOD_PUB_GET BT_MESH_MODEL_OP_2(0x80, 0x18)
#define OP_MOD_PUB_STATUS BT_MESH_MODEL_OP_2(0x80, 0x19)
#define OP_MOD_PUB_VA_SET BT_MESH_MODEL_OP_2(0x80, 0x1a)
#define OP_MOD_SUB_ADD BT_MESH_MODEL_OP_2(0x80, 0x1b)
#define OP_MOD_SUB_DEL BT_MESH_MODEL_OP_2(0x80, 0x1c)
#define OP_MOD_SUB_DEL_ALL BT_MESH_MODEL_OP_2(0x80, 0x1d)
#define OP_MOD_SUB_OVERWRITE BT_MESH_MODEL_OP_2(0x80, 0x1e)
#define OP_MOD_SUB_STATUS BT_MESH_MODEL_OP_2(0x80, 0x1f)
#define OP_MOD_SUB_VA_ADD BT_MESH_MODEL_OP_2(0x80, 0x20)
#define OP_MOD_SUB_VA_DEL BT_MESH_MODEL_OP_2(0x80, 0x21)
#define OP_MOD_SUB_VA_OVERWRITE BT_MESH_MODEL_OP_2(0x80, 0x22)
#define OP_NET_TRANSMIT_GET BT_MESH_MODEL_OP_2(0x80, 0x23)
#define OP_NET_TRANSMIT_SET BT_MESH_MODEL_OP_2(0x80, 0x24)
#define OP_NET_TRANSMIT_STATUS BT_MESH_MODEL_OP_2(0x80, 0x25)
#define OP_RELAY_GET BT_MESH_MODEL_OP_2(0x80, 0x26)
#define OP_RELAY_SET BT_MESH_MODEL_OP_2(0x80, 0x27)
#define OP_RELAY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x28)
#define OP_MOD_SUB_GET BT_MESH_MODEL_OP_2(0x80, 0x29)
#define OP_MOD_SUB_LIST BT_MESH_MODEL_OP_2(0x80, 0x2a)
#define OP_MOD_SUB_GET_VND BT_MESH_MODEL_OP_2(0x80, 0x2b)
#define OP_MOD_SUB_LIST_VND BT_MESH_MODEL_OP_2(0x80, 0x2c)
#define OP_LPN_TIMEOUT_GET BT_MESH_MODEL_OP_2(0x80, 0x2d)
#define OP_LPN_TIMEOUT_STATUS BT_MESH_MODEL_OP_2(0x80, 0x2e)
#define OP_HEALTH_FAULT_CLEAR BT_MESH_MODEL_OP_2(0x80, 0x2f)
#define OP_HEALTH_FAULT_CLEAR_UNREL BT_MESH_MODEL_OP_2(0x80, 0x30)
#define OP_HEALTH_FAULT_GET BT_MESH_MODEL_OP_2(0x80, 0x31)
#define OP_HEALTH_FAULT_TEST BT_MESH_MODEL_OP_2(0x80, 0x32)
#define OP_HEALTH_FAULT_TEST_UNREL BT_MESH_MODEL_OP_2(0x80, 0x33)
#define OP_HEALTH_PERIOD_GET BT_MESH_MODEL_OP_2(0x80, 0x34)
#define OP_HEALTH_PERIOD_SET BT_MESH_MODEL_OP_2(0x80, 0x35)
#define OP_HEALTH_PERIOD_SET_UNREL BT_MESH_MODEL_OP_2(0x80, 0x36)
#define OP_HEALTH_PERIOD_STATUS BT_MESH_MODEL_OP_2(0x80, 0x37)
#define OP_HEARTBEAT_PUB_GET BT_MESH_MODEL_OP_2(0x80, 0x38)
#define OP_HEARTBEAT_PUB_SET BT_MESH_MODEL_OP_2(0x80, 0x39)
#define OP_HEARTBEAT_SUB_GET BT_MESH_MODEL_OP_2(0x80, 0x3a)
#define OP_HEARTBEAT_SUB_SET BT_MESH_MODEL_OP_2(0x80, 0x3b)
#define OP_HEARTBEAT_SUB_STATUS BT_MESH_MODEL_OP_2(0x80, 0x3c)
#define OP_MOD_APP_BIND BT_MESH_MODEL_OP_2(0x80, 0x3d)
#define OP_MOD_APP_STATUS BT_MESH_MODEL_OP_2(0x80, 0x3e)
#define OP_MOD_APP_UNBIND BT_MESH_MODEL_OP_2(0x80, 0x3f)
#define OP_NET_KEY_ADD BT_MESH_MODEL_OP_2(0x80, 0x40)
#define OP_NET_KEY_DEL BT_MESH_MODEL_OP_2(0x80, 0x41)
#define OP_NET_KEY_GET BT_MESH_MODEL_OP_2(0x80, 0x42)
#define OP_NET_KEY_LIST BT_MESH_MODEL_OP_2(0x80, 0x43)
#define OP_NET_KEY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x44)
#define OP_NET_KEY_UPDATE BT_MESH_MODEL_OP_2(0x80, 0x45)
#define OP_NODE_IDENTITY_GET BT_MESH_MODEL_OP_2(0x80, 0x46)
#define OP_NODE_IDENTITY_SET BT_MESH_MODEL_OP_2(0x80, 0x47)
#define OP_NODE_IDENTITY_STATUS BT_MESH_MODEL_OP_2(0x80, 0x48)
#define OP_NODE_RESET BT_MESH_MODEL_OP_2(0x80, 0x49)
#define OP_NODE_RESET_STATUS BT_MESH_MODEL_OP_2(0x80, 0x4a)
#define OP_SIG_MOD_APP_GET BT_MESH_MODEL_OP_2(0x80, 0x4b)
#define OP_SIG_MOD_APP_LIST BT_MESH_MODEL_OP_2(0x80, 0x4c)
#define OP_VND_MOD_APP_GET BT_MESH_MODEL_OP_2(0x80, 0x4d)
#define OP_VND_MOD_APP_LIST BT_MESH_MODEL_OP_2(0x80, 0x4e)
#define STATUS_SUCCESS 0x00
#define STATUS_INVALID_ADDRESS 0x01
#define STATUS_INVALID_MODEL 0x02
#define STATUS_INVALID_APPKEY 0x03
#define STATUS_INVALID_NETKEY 0x04
#define STATUS_INSUFF_RESOURCES 0x05
#define STATUS_IDX_ALREADY_STORED 0x06
#define STATUS_NVAL_PUB_PARAM 0x07
#define STATUS_NOT_SUB_MOD 0x08
#define STATUS_STORAGE_FAIL 0x09
#define STATUS_FEAT_NOT_SUPP 0x0a
#define STATUS_CANNOT_UPDATE 0x0b
#define STATUS_CANNOT_REMOVE 0x0c
#define STATUS_CANNOT_BIND 0x0d
#define STATUS_TEMP_STATE_CHG_FAIL 0x0e
#define STATUS_CANNOT_SET 0x0f
#define STATUS_UNSPECIFIED 0x10
#define STATUS_INVALID_BINDING 0x11
int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary);
int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary);
int bt_mesh_cfg_cli_init(struct bt_mesh_model *model, bool primary);
int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary);
void bt_mesh_cfg_reset(void);
void bt_mesh_heartbeat(u16_t src, u16_t dst, u8_t hops, u16_t feat);
void bt_mesh_attention(struct bt_mesh_model *model, u8_t time);
u8_t *bt_mesh_label_uuid_get(u16_t addr);
u8_t bt_mesh_net_transmit_get(void);
u8_t bt_mesh_relay_get(void);
u8_t bt_mesh_friend_get(void);
u8_t bt_mesh_relay_retransmit_get(void);
u8_t bt_mesh_beacon_get(void);
u8_t bt_mesh_gatt_proxy_get(void);
u8_t bt_mesh_default_ttl_get(void);
#include <misc/byteorder.h>
static inline void key_idx_pack(struct net_buf_simple *buf,
u16_t idx1, u16_t idx2)
{
net_buf_simple_add_le16(buf, idx1 | ((idx2 & 0x00f) << 12));
net_buf_simple_add_u8(buf, idx2 >> 4);
}
static inline void key_idx_unpack(struct net_buf_simple *buf,
u16_t *idx1, u16_t *idx2)
{
*idx1 = sys_get_le16(&buf->data[0]) & 0xfff;
*idx2 = sys_get_le16(&buf->data[1]) >> 4;
net_buf_simple_pull(buf, 3);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,44 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
enum bt_mesh_friend_pdu_type {
BT_MESH_FRIEND_PDU_SINGLE,
BT_MESH_FRIEND_PDU_PARTIAL,
BT_MESH_FRIEND_PDU_COMPLETE,
};
bool bt_mesh_friend_match(u16_t net_idx, u16_t addr);
struct bt_mesh_friend *bt_mesh_friend_find(u16_t net_idx, u16_t lpn_addr,
bool valid, bool established);
void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, struct net_buf_simple *sbuf);
bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, struct net_buf_simple *sbuf);
void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
u16_t dst, u64_t *seq_auth);
void bt_mesh_friend_sec_update(u16_t net_idx);
void bt_mesh_friend_clear_net_idx(u16_t net_idx);
int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf);
int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf);
int bt_mesh_friend_clear(struct bt_mesh_net_rx *rx, struct net_buf_simple *buf);
int bt_mesh_friend_clear_cfm(struct bt_mesh_net_rx *rx,
struct net_buf_simple *buf);
int bt_mesh_friend_sub_add(struct bt_mesh_net_rx *rx,
struct net_buf_simple *buf);
int bt_mesh_friend_sub_rem(struct bt_mesh_net_rx *rx,
struct net_buf_simple *buf);
int bt_mesh_friend_init(void);

View file

@ -0,0 +1,515 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include <zephyr/types.h>
#include <misc/util.h>
#include <misc/byteorder.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_MODEL)
#include "common/log.h"
#include "foundation.h"
static s32_t msg_timeout = K_SECONDS(2);
static struct bt_mesh_health_cli *health_cli;
struct health_fault_param {
u16_t cid;
u8_t *expect_test_id;
u8_t *test_id;
u8_t *faults;
size_t *fault_count;
};
static void health_fault_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct health_fault_param *param;
u8_t test_id;
u16_t cid;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
bt_hex(buf->data, buf->len));
if (health_cli->op_pending != OP_HEALTH_FAULT_STATUS) {
BT_WARN("Unexpected Health Fault Status message");
return;
}
param = health_cli->op_param;
test_id = net_buf_simple_pull_u8(buf);
if (param->expect_test_id && test_id != *param->expect_test_id) {
BT_WARN("Health fault with unexpected Test ID");
return;
}
cid = net_buf_simple_pull_le16(buf);
if (cid != param->cid) {
BT_WARN("Health fault with unexpected Company ID");
return;
}
if (param->test_id) {
*param->test_id = test_id;
}
if (buf->len > *param->fault_count) {
BT_WARN("Got more faults than there's space for");
} else {
*param->fault_count = buf->len;
}
memcpy(param->faults, buf->data, *param->fault_count);
k_sem_give(&health_cli->op_sync);
}
static void health_current_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct bt_mesh_health_cli *cli = model->user_data;
u8_t test_id;
u16_t cid;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
bt_hex(buf->data, buf->len));
test_id = net_buf_simple_pull_u8(buf);
cid = net_buf_simple_pull_le16(buf);
BT_DBG("Test ID 0x%02x Company ID 0x%04x Fault Count %u",
test_id, cid, buf->len);
if (!cli->current_status) {
BT_WARN("No Current Status callback available");
return;
}
cli->current_status(cli, ctx->addr, test_id, cid, buf->data, buf->len);
}
struct health_period_param {
u8_t *divisor;
};
static void health_period_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct health_period_param *param;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
bt_hex(buf->data, buf->len));
if (health_cli->op_pending != OP_HEALTH_PERIOD_STATUS) {
BT_WARN("Unexpected Health Period Status message");
return;
}
param = health_cli->op_param;
*param->divisor = net_buf_simple_pull_u8(buf);
k_sem_give(&health_cli->op_sync);
}
struct health_attention_param {
u8_t *attention;
};
static void health_attention_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct health_attention_param *param;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
ctx->net_idx, ctx->app_idx, ctx->addr, buf->len,
bt_hex(buf->data, buf->len));
if (health_cli->op_pending != OP_ATTENTION_STATUS) {
BT_WARN("Unexpected Health Attention Status message");
return;
}
param = health_cli->op_param;
*param->attention = net_buf_simple_pull_u8(buf);
k_sem_give(&health_cli->op_sync);
}
const struct bt_mesh_model_op bt_mesh_health_cli_op[] = {
{ OP_HEALTH_FAULT_STATUS, 3, health_fault_status },
{ OP_HEALTH_CURRENT_STATUS, 3, health_current_status },
{ OP_HEALTH_PERIOD_STATUS, 1, health_period_status },
{ OP_ATTENTION_STATUS, 1, health_attention_status },
BT_MESH_MODEL_OP_END,
};
static int check_cli(void)
{
if (!health_cli) {
BT_ERR("No available Health Client context!");
return -EINVAL;
}
if (health_cli->op_pending) {
BT_WARN("Another synchronous operation pending");
return -EBUSY;
}
return 0;
}
static int cli_wait(void *param, u32_t op)
{
int err;
health_cli->op_param = param;
health_cli->op_pending = op;
err = k_sem_take(&health_cli->op_sync, msg_timeout);
health_cli->op_pending = 0;
health_cli->op_param = NULL;
return err;
}
int bt_mesh_health_attention_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *attention)
{
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
struct health_attention_param param = {
.attention = attention,
};
int err;
err = check_cli();
if (err) {
return err;
}
bt_mesh_model_msg_init(msg, OP_ATTENTION_GET);
err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
return err;
}
return cli_wait(&param, OP_ATTENTION_STATUS);
}
int bt_mesh_health_attention_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t attention, u8_t *updated_attention)
{
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
struct health_attention_param param = {
.attention = updated_attention,
};
int err;
err = check_cli();
if (err) {
return err;
}
if (updated_attention) {
bt_mesh_model_msg_init(msg, OP_ATTENTION_SET);
} else {
bt_mesh_model_msg_init(msg, OP_ATTENTION_SET_UNREL);
}
net_buf_simple_add_u8(msg, attention);
err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
return err;
}
if (!updated_attention) {
return 0;
}
return cli_wait(&param, OP_ATTENTION_STATUS);
}
int bt_mesh_health_period_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *divisor)
{
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
struct health_period_param param = {
.divisor = divisor,
};
int err;
err = check_cli();
if (err) {
return err;
}
bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_GET);
err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
return err;
}
return cli_wait(&param, OP_HEALTH_PERIOD_STATUS);
}
int bt_mesh_health_period_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t divisor, u8_t *updated_divisor)
{
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
struct health_period_param param = {
.divisor = updated_divisor,
};
int err;
err = check_cli();
if (err) {
return err;
}
if (updated_divisor) {
bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_SET);
} else {
bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_SET_UNREL);
}
net_buf_simple_add_u8(msg, divisor);
err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
return err;
}
if (!updated_divisor) {
return 0;
}
return cli_wait(&param, OP_HEALTH_PERIOD_STATUS);
}
int bt_mesh_health_fault_test(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t test_id, u8_t *faults,
size_t *fault_count)
{
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 3 + 4);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
struct health_fault_param param = {
.cid = cid,
.expect_test_id = &test_id,
.faults = faults,
.fault_count = fault_count,
};
int err;
err = check_cli();
if (err) {
return err;
}
if (faults) {
bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_TEST);
} else {
bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_TEST_UNREL);
}
net_buf_simple_add_u8(msg, test_id);
net_buf_simple_add_le16(msg, cid);
err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
return err;
}
if (!faults) {
return 0;
}
return cli_wait(&param, OP_HEALTH_FAULT_STATUS);
}
int bt_mesh_health_fault_clear(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count)
{
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 2 + 4);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
struct health_fault_param param = {
.cid = cid,
.test_id = test_id,
.faults = faults,
.fault_count = fault_count,
};
int err;
err = check_cli();
if (err) {
return err;
}
if (test_id) {
bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_CLEAR);
} else {
bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_CLEAR_UNREL);
}
net_buf_simple_add_le16(msg, cid);
err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
return err;
}
if (!test_id) {
return 0;
}
return cli_wait(&param, OP_HEALTH_FAULT_STATUS);
}
int bt_mesh_health_fault_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count)
{
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 2 + 4);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
struct health_fault_param param = {
.cid = cid,
.test_id = test_id,
.faults = faults,
.fault_count = fault_count,
};
int err;
err = check_cli();
if (err) {
return err;
}
bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_GET);
net_buf_simple_add_le16(msg, cid);
err = bt_mesh_model_send(health_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
return err;
}
return cli_wait(&param, OP_HEALTH_FAULT_STATUS);
}
s32_t bt_mesh_health_cli_timeout_get(void)
{
return msg_timeout;
}
void bt_mesh_health_cli_timeout_set(s32_t timeout)
{
msg_timeout = timeout;
}
int bt_mesh_health_cli_set(struct bt_mesh_model *model)
{
if (!model->user_data) {
BT_ERR("No Health Client context for given model");
return -EINVAL;
}
health_cli = model->user_data;
return 0;
}
int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary)
{
struct bt_mesh_health_cli *cli = model->user_data;
BT_DBG("primary %u", primary);
if (!cli) {
BT_ERR("No Health Client context provided");
return -EINVAL;
}
cli = model->user_data;
cli->model = model;
k_sem_init(&cli->op_sync, 0, 1);
/* Set the default health client pointer */
if (!health_cli) {
health_cli = cli;
}
return 0;
}

View file

@ -0,0 +1,435 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include <zephyr/types.h>
#include <misc/byteorder.h>
#include <misc/util.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_MODEL)
#include "common/log.h"
#include "mesh.h"
#include "adv.h"
#include "net.h"
#include "transport.h"
#include "access.h"
#include "foundation.h"
#define HEALTH_TEST_STANDARD 0x00
/* Health Server context of the primary element */
struct bt_mesh_health_srv *health_srv;
static void health_get_registered(struct bt_mesh_model *mod,
u16_t company_id,
struct net_buf_simple *msg)
{
struct bt_mesh_health_srv *srv = mod->user_data;
u8_t *test_id;
BT_DBG("Company ID 0x%04x", company_id);
bt_mesh_model_msg_init(msg, OP_HEALTH_FAULT_STATUS);
test_id = net_buf_simple_add(msg, 1);
net_buf_simple_add_le16(msg, company_id);
if (srv->cb && srv->cb->fault_get_reg) {
u8_t fault_count = net_buf_simple_tailroom(msg) - 4;
int err;
err = srv->cb->fault_get_reg(mod, company_id, test_id,
net_buf_simple_tail(msg),
&fault_count);
if (err) {
BT_ERR("Failed to get faults (err %d)", err);
*test_id = HEALTH_TEST_STANDARD;
} else {
net_buf_simple_add(msg, fault_count);
}
} else {
BT_WARN("No callback for getting faults");
*test_id = HEALTH_TEST_STANDARD;
}
}
static size_t health_get_current(struct bt_mesh_model *mod,
struct net_buf_simple *msg)
{
struct bt_mesh_health_srv *srv = mod->user_data;
const struct bt_mesh_comp *comp;
u8_t *test_id, *company_ptr;
u16_t company_id;
u8_t fault_count;
int err;
bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS);
test_id = net_buf_simple_add(msg, 1);
company_ptr = net_buf_simple_add(msg, sizeof(company_id));
comp = bt_mesh_comp_get();
if (srv->cb && srv->cb->fault_get_cur) {
fault_count = net_buf_simple_tailroom(msg);
err = srv->cb->fault_get_cur(mod, test_id, &company_id,
net_buf_simple_tail(msg),
&fault_count);
if (err) {
BT_ERR("Failed to get faults (err %d)", err);
sys_put_le16(comp->cid, company_ptr);
*test_id = HEALTH_TEST_STANDARD;
fault_count = 0;
} else {
sys_put_le16(company_id, company_ptr);
net_buf_simple_add(msg, fault_count);
}
} else {
BT_WARN("No callback for getting faults");
sys_put_le16(comp->cid, company_ptr);
*test_id = HEALTH_TEST_STANDARD;
fault_count = 0;
}
return fault_count;
}
static void health_fault_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct net_buf_simple *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
u16_t company_id;
company_id = net_buf_simple_pull_le16(buf);
BT_DBG("company_id 0x%04x", company_id);
health_get_registered(model, company_id, sdu);
if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) {
BT_ERR("Unable to send Health Current Status response");
}
}
static void health_fault_clear_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
company_id = net_buf_simple_pull_le16(buf);
BT_DBG("company_id 0x%04x", company_id);
if (srv->cb && srv->cb->fault_clear) {
srv->cb->fault_clear(model, company_id);
}
}
static void health_fault_clear(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct net_buf_simple *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
company_id = net_buf_simple_pull_le16(buf);
BT_DBG("company_id 0x%04x", company_id);
if (srv->cb && srv->cb->fault_clear) {
srv->cb->fault_clear(model, company_id);
}
health_get_registered(model, company_id, sdu);
if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) {
BT_ERR("Unable to send Health Current Status response");
}
}
static void health_fault_test_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
u8_t test_id;
test_id = net_buf_simple_pull_u8(buf);
company_id = net_buf_simple_pull_le16(buf);
BT_DBG("test 0x%02x company 0x%04x", test_id, company_id);
if (srv->cb && srv->cb->fault_test) {
srv->cb->fault_test(model, test_id, company_id);
}
}
static void health_fault_test(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
struct net_buf_simple *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
u8_t test_id;
BT_DBG("");
test_id = net_buf_simple_pull_u8(buf);
company_id = net_buf_simple_pull_le16(buf);
BT_DBG("test 0x%02x company 0x%04x", test_id, company_id);
if (srv->cb && srv->cb->fault_test) {
int err;
err = srv->cb->fault_test(model, test_id, company_id);
if (err) {
BT_WARN("Running fault test failed with err %d", err);
return;
}
}
health_get_registered(model, company_id, sdu);
if (bt_mesh_model_send(model, ctx, sdu, NULL, NULL)) {
BT_ERR("Unable to send Health Current Status response");
}
}
static void send_attention_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct bt_mesh_health_srv *srv = model->user_data;
u8_t time;
time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000;
BT_DBG("%u second%s", time, (time == 1) ? "" : "s");
bt_mesh_model_msg_init(msg, OP_ATTENTION_STATUS);
net_buf_simple_add_u8(msg, time);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
BT_ERR("Unable to send Attention Status");
}
}
static void attention_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
BT_DBG("");
send_attention_status(model, ctx);
}
static void attention_set_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
u8_t time;
time = net_buf_simple_pull_u8(buf);
BT_DBG("%u second%s", time, (time == 1) ? "" : "s");
bt_mesh_attention(model, time);
}
static void attention_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
BT_DBG("");
attention_set_unrel(model, ctx, buf);
send_attention_status(model, ctx);
}
static void send_health_period_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct net_buf_simple *msg = NET_BUF_SIMPLE(2 + 1 + 4);
bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_STATUS);
net_buf_simple_add_u8(msg, model->pub->period_div);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
BT_ERR("Unable to send Health Period Status");
}
}
static void health_period_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
BT_DBG("");
send_health_period_status(model, ctx);
}
static void health_period_set_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
u8_t period;
period = net_buf_simple_pull_u8(buf);
if (period > 15) {
BT_WARN("Prohibited period value %u", period);
return;
}
BT_DBG("period %u", period);
model->pub->period_div = period;
}
static void health_period_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct net_buf_simple *buf)
{
BT_DBG("");
health_period_set_unrel(model, ctx, buf);
send_health_period_status(model, ctx);
}
const struct bt_mesh_model_op bt_mesh_health_srv_op[] = {
{ OP_HEALTH_FAULT_GET, 2, health_fault_get },
{ OP_HEALTH_FAULT_CLEAR, 2, health_fault_clear },
{ OP_HEALTH_FAULT_CLEAR_UNREL, 2, health_fault_clear_unrel },
{ OP_HEALTH_FAULT_TEST, 3, health_fault_test },
{ OP_HEALTH_FAULT_TEST_UNREL, 3, health_fault_test_unrel },
{ OP_HEALTH_PERIOD_GET, 0, health_period_get },
{ OP_HEALTH_PERIOD_SET, 1, health_period_set },
{ OP_HEALTH_PERIOD_SET_UNREL, 1, health_period_set_unrel },
{ OP_ATTENTION_GET, 0, attention_get },
{ OP_ATTENTION_SET, 1, attention_set },
{ OP_ATTENTION_SET_UNREL, 1, attention_set_unrel },
BT_MESH_MODEL_OP_END,
};
static int health_pub_update(struct bt_mesh_model *mod)
{
struct bt_mesh_model_pub *pub = mod->pub;
size_t count;
BT_DBG("");
count = health_get_current(mod, pub->msg);
if (!count) {
pub->period_div = 0;
}
return 0;
}
int bt_mesh_fault_update(struct bt_mesh_elem *elem)
{
struct bt_mesh_model *mod;
mod = bt_mesh_model_find(elem, BT_MESH_MODEL_ID_HEALTH_SRV);
if (!mod) {
return -EINVAL;
}
return bt_mesh_model_publish(mod);
}
static void attention_off(struct k_work *work)
{
struct bt_mesh_health_srv *srv = CONTAINER_OF(work,
struct bt_mesh_health_srv,
attn_timer.work);
BT_DBG("");
if (srv->cb && srv->cb->attn_off) {
srv->cb->attn_off(srv->model);
}
}
int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary)
{
struct bt_mesh_health_srv *srv = model->user_data;
if (!srv) {
if (!primary) {
return 0;
}
BT_ERR("No Health Server context provided");
return -EINVAL;
}
if (!model->pub) {
BT_ERR("Health Server has no publication support");
return -EINVAL;
}
model->pub->update = health_pub_update,
k_delayed_work_init(&srv->attn_timer, attention_off);
srv->model = model;
if (primary) {
health_srv = srv;
}
return 0;
}
void bt_mesh_attention(struct bt_mesh_model *model, u8_t time)
{
struct bt_mesh_health_srv *srv;
if (!model) {
srv = health_srv;
if (!srv) {
BT_WARN("No Health Server available");
return;
}
model = srv->model;
} else {
srv = model->user_data;
}
if (time) {
if (srv->cb && srv->cb->attn_on) {
srv->cb->attn_on(model);
}
k_delayed_work_submit(&srv->attn_timer, time * 1000);
} else {
k_delayed_work_cancel(&srv->attn_timer);
if (srv->cb && srv->cb->attn_off) {
srv->cb->attn_off(model);
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,62 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
struct net_buf_simple *buf);
int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
struct net_buf_simple *buf);
int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx,
struct net_buf_simple *buf);
int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx,
struct net_buf_simple *buf);
static inline bool bt_mesh_lpn_established(void)
{
#if defined(CONFIG_BT_MESH_LOW_POWER)
return bt_mesh.lpn.established;
#else
return false;
#endif
}
static inline bool bt_mesh_lpn_match(u16_t addr)
{
#if defined(CONFIG_BT_MESH_LOW_POWER)
if (bt_mesh_lpn_established()) {
return (addr == bt_mesh.lpn.frnd);
}
#endif
return false;
}
static inline bool bt_mesh_lpn_waiting_update(void)
{
#if defined(CONFIG_BT_MESH_LOW_POWER)
return (bt_mesh.lpn.state == BT_MESH_LPN_WAIT_UPDATE);
#else
return false;
#endif
}
static inline bool bt_mesh_lpn_timer(void)
{
#if defined(CONFIG_BT_MESH_LPN_AUTO)
return (bt_mesh.lpn.state == BT_MESH_LPN_TIMER);
#else
return false;
#endif
}
void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx);
void bt_mesh_lpn_group_add(u16_t group);
void bt_mesh_lpn_group_del(u16_t *groups, size_t group_count);
void bt_mesh_lpn_disable(bool force);
int bt_mesh_lpn_init(void);

View file

@ -0,0 +1,226 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <stdbool.h>
#include <errno.h>
#include <net/buf.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/mesh.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG)
#include "common/log.h"
#include "test.h"
#include "adv.h"
#include "prov.h"
#include "net.h"
#include "beacon.h"
#include "lpn.h"
#include "friend.h"
#include "transport.h"
#include "access.h"
#include "foundation.h"
#include "proxy.h"
#include "mesh.h"
static bool provisioned;
int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
u8_t flags, u32_t iv_index, u32_t seq,
u16_t addr, const u8_t dev_key[16])
{
int err;
BT_INFO("Primary Element: 0x%04x", addr);
BT_DBG("net_idx 0x%04x flags 0x%02x iv_index 0x%04x",
net_idx, flags, iv_index);
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
bt_mesh_proxy_prov_disable();
}
err = bt_mesh_net_create(net_idx, flags, net_key, iv_index);
if (err) {
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
bt_mesh_proxy_prov_enable();
}
return err;
}
bt_mesh.seq = seq;
bt_mesh_comp_provision(addr);
memcpy(bt_mesh.dev_key, dev_key, 16);
provisioned = true;
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) {
bt_mesh_beacon_enable();
} else {
bt_mesh_beacon_disable();
}
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED) {
bt_mesh_proxy_gatt_enable();
bt_mesh_adv_update();
}
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
bt_mesh_lpn_init();
} else {
bt_mesh_scan_enable();
}
if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
bt_mesh_friend_init();
}
if (IS_ENABLED(CONFIG_BT_MESH_PROV)) {
bt_mesh_prov_complete(net_idx, addr);
}
return 0;
}
void bt_mesh_reset(void)
{
if (!provisioned) {
return;
}
bt_mesh_comp_unprovision();
bt_mesh.iv_index = 0;
bt_mesh.seq = 0;
bt_mesh.iv_update = 0;
bt_mesh.pending_update = 0;
bt_mesh.valid = 0;
bt_mesh.last_update = 0;
bt_mesh.ivu_initiator = 0;
k_delayed_work_cancel(&bt_mesh.ivu_complete);
bt_mesh_cfg_reset();
bt_mesh_rx_reset();
bt_mesh_tx_reset();
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
bt_mesh_lpn_disable(true);
}
if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
bt_mesh_friend_clear_net_idx(BT_MESH_KEY_ANY);
}
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
bt_mesh_proxy_gatt_disable();
}
memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl));
provisioned = false;
bt_mesh_scan_disable();
bt_mesh_beacon_disable();
if (IS_ENABLED(CONFIG_BT_MESH_PROV)) {
bt_mesh_prov_reset();
}
}
bool bt_mesh_is_provisioned(void)
{
return provisioned;
}
int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers)
{
if (bt_mesh_is_provisioned()) {
return -EALREADY;
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&
(bearers & BT_MESH_PROV_ADV)) {
/* Make sure we're scanning for provisioning inviations */
bt_mesh_scan_enable();
/* Enable unprovisioned beacon sending */
bt_mesh_beacon_enable();
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
(bearers & BT_MESH_PROV_GATT)) {
bt_mesh_proxy_prov_enable();
bt_mesh_adv_update();
}
return 0;
}
int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers)
{
if (bt_mesh_is_provisioned()) {
return -EALREADY;
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&
(bearers & BT_MESH_PROV_ADV)) {
bt_mesh_beacon_disable();
bt_mesh_scan_disable();
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
(bearers & BT_MESH_PROV_GATT)) {
bt_mesh_proxy_prov_disable();
bt_mesh_adv_update();
}
return 0;
}
int bt_mesh_init(const struct bt_mesh_prov *prov,
const struct bt_mesh_comp *comp)
{
int err;
err = bt_mesh_test();
if (err) {
return err;
}
err = bt_mesh_comp_register(comp);
if (err) {
return err;
}
if (IS_ENABLED(CONFIG_BT_MESH_PROV)) {
err = bt_mesh_prov_init(prov);
if (err) {
return err;
}
}
bt_mesh_net_init();
bt_mesh_trans_init();
bt_mesh_beacon_init();
bt_mesh_adv_init();
if (IS_ENABLED(CONFIG_BT_MESH_PROXY)) {
bt_mesh_proxy_init();
}
return 0;
}

View file

@ -0,0 +1,19 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define BT_MESH_KEY_PRIMARY 0x0000
#define BT_MESH_KEY_ANY 0xffff
#define BT_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000)
#define BT_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) <= 0xff00)
#define BT_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xc000)
#define BT_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfffb)
struct bt_mesh_net;
bool bt_mesh_is_provisioned(void);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,329 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define BT_MESH_NET_FLAG_KR BIT(0)
#define BT_MESH_NET_FLAG_IVU BIT(1)
#define BT_MESH_KR_NORMAL 0x00
#define BT_MESH_KR_PHASE_1 0x01
#define BT_MESH_KR_PHASE_2 0x02
#define BT_MESH_KR_PHASE_3 0x03
#define BT_MESH_IV_UPDATE(flags) ((flags >> 1) & 0x01)
#define BT_MESH_KEY_REFRESH(flags) (flags & 0x01)
struct bt_mesh_app_key {
u16_t net_idx;
u16_t app_idx;
bool updated;
struct bt_mesh_app_keys {
u8_t id;
u8_t val[16];
} keys[2];
};
struct bt_mesh_subnet {
u32_t beacon_sent; /* Timestamp of last sent beacon */
u8_t beacons_last; /* Number of beacons during last
* observation window
*/
u8_t beacons_cur; /* Number of beaconds observed during
* currently ongoing window.
*/
u8_t beacon_cache[21]; /* Cached last authenticated beacon */
u16_t net_idx; /* NetKeyIndex */
bool kr_flag; /* Key Refresh Flag */
u8_t kr_phase; /* Key Refresh Phase */
u8_t node_id; /* Node Identity State */
u32_t node_id_start; /* Node Identity started timestamp */
u8_t auth[8]; /* Beacon Authentication Value */
struct bt_mesh_subnet_keys {
u8_t net[16]; /* NetKey */
u8_t nid; /* NID */
u8_t enc[16]; /* EncKey */
u8_t net_id[8]; /* Network ID */
#if defined(CONFIG_BT_MESH_GATT_PROXY)
u8_t identity[16]; /* IdentityKey */
#endif
u8_t privacy[16]; /* PrivacyKey */
u8_t beacon[16]; /* BeaconKey */
} keys[2];
};
struct bt_mesh_rpl {
u16_t src;
bool old_iv;
u32_t seq;
};
#if defined(CONFIG_BT_MESH_FRIEND)
#define FRIEND_SEG_RX CONFIG_BT_MESH_FRIEND_SEG_RX
#define FRIEND_SUB_LIST_SIZE CONFIG_BT_MESH_FRIEND_SUB_LIST_SIZE
#else
#define FRIEND_SEG_RX 0
#define FRIEND_SUB_LIST_SIZE 0
#endif
struct bt_mesh_friend {
u16_t lpn;
u8_t recv_delay;
u8_t fsn:1,
send_last:1,
pending_req:1,
sec_update:1,
pending_buf:1,
valid:1,
established:1;
s32_t poll_to;
u16_t lpn_counter;
u16_t counter;
u16_t net_idx;
u16_t sub_list[FRIEND_SUB_LIST_SIZE];
struct k_delayed_work timer;
struct bt_mesh_friend_seg {
sys_slist_t queue;
} seg[FRIEND_SEG_RX];
struct net_buf *last;
sys_slist_t queue;
u32_t queue_size;
/* Friend Clear Procedure */
struct {
u32_t start; /* Clear Procedure start */
u16_t frnd; /* Previous Friend's address */
u16_t repeat_sec; /* Repeat timeout in seconds */
struct k_delayed_work timer; /* Repeat timer */
} clear;
};
#if defined(CONFIG_BT_MESH_LOW_POWER)
#define LPN_GROUPS CONFIG_BT_MESH_LOW_POWER
#else
#define LPN_GROUPS 0
#endif
/* Low Power Node state */
struct bt_mesh_lpn {
enum __packed {
BT_MESH_LPN_DISABLED, /* LPN feature is disabled */
BT_MESH_LPN_CLEAR, /* Clear in progress */
BT_MESH_LPN_TIMER, /* Waiting for auto timer expiry */
BT_MESH_LPN_ENABLED, /* LPN enabled, but no Friend */
BT_MESH_LPN_REQ_WAIT, /* Wait before scanning for offers */
BT_MESH_LPN_WAIT_OFFER, /* Friend Req sent */
BT_MESH_LPN_ESTABLISHED, /* Friendship established */
BT_MESH_LPN_RECV_DELAY, /* Poll sent, waiting ReceiveDelay */
BT_MESH_LPN_WAIT_UPDATE, /* Waiting for Update or message */
} state;
/* Transaction Number (used for subscription list) */
u8_t xact_next;
u8_t xact_pending;
u8_t sent_req;
/* Address of our Friend when we're a LPN. Unassigned if we don't
* have a friend yet.
*/
u16_t frnd;
/* Value from the friend offer */
u8_t recv_win;
u8_t req_attempts; /* Number of Request attempts */
s32_t poll_timeout;
u8_t groups_changed:1, /* Friend Subscription List needs updating */
pending_poll:1, /* Poll to be sent after subscription */
disable:1, /* Disable LPN after clearing */
fsn:1, /* Friend Sequence Number */
established:1, /* Friendship established */
clear_success:1; /* Friend Clear Confirm received */
/* Friend Queue Size */
u8_t queue_size;
/* LPNCounter */
u16_t counter;
/* Previous Friend of this LPN */
u16_t old_friend;
/* Duration reported for last advertising packet */
u16_t adv_duration;
/* Next LPN related action timer */
struct k_delayed_work timer;
/* Subscribed groups */
u16_t groups[LPN_GROUPS];
/* Bit fields for tracking which groups the Friend knows about */
ATOMIC_DEFINE(added, LPN_GROUPS);
ATOMIC_DEFINE(pending, LPN_GROUPS);
ATOMIC_DEFINE(to_remove, LPN_GROUPS);
};
struct bt_mesh_net {
u32_t iv_index; /* Current IV Index */
u32_t seq:24, /* Next outgoing sequence number */
iv_update:1, /* 1 if IV Update in Progress */
ivu_initiator:1, /* IV Update initiated by us */
ivu_test:1, /* IV Update test mode */
pending_update:1, /* Update blocked by SDU in progress */
valid:1; /* 0 if unused */
s64_t last_update; /* Time since last IV Update change */
/* Local network interface */
struct k_work local_work;
sys_slist_t local_queue;
#if defined(CONFIG_BT_MESH_FRIEND)
/* Friend state, unique for each LPN that we're Friends for */
struct bt_mesh_friend frnd[CONFIG_BT_MESH_FRIEND_LPN_COUNT];
#endif
#if defined(CONFIG_BT_MESH_LOW_POWER)
struct bt_mesh_lpn lpn; /* Low Power Node state */
#endif
/* Timer to transition IV Update in Progress state */
struct k_delayed_work ivu_complete;
u8_t dev_key[16];
struct bt_mesh_app_key app_keys[CONFIG_BT_MESH_APP_KEY_COUNT];
struct bt_mesh_subnet sub[CONFIG_BT_MESH_SUBNET_COUNT];
struct bt_mesh_rpl rpl[CONFIG_BT_MESH_CRPL];
};
/* Network interface */
enum bt_mesh_net_if {
BT_MESH_NET_IF_ADV,
BT_MESH_NET_IF_LOCAL,
BT_MESH_NET_IF_PROXY,
BT_MESH_NET_IF_PROXY_CFG,
};
/* Decoding context for Network/Transport data */
struct bt_mesh_net_rx {
struct bt_mesh_subnet *sub;
struct bt_mesh_msg_ctx ctx;
u32_t seq; /* Sequence Number */
u16_t dst; /* Destination address */
u8_t old_iv:1, /* iv_index - 1 was used */
new_key:1, /* Data was encrypted with updated key */
friend_cred:1, /* Data was encrypted with friend cred */
ctl:1, /* Network Control */
net_if:2, /* Network interface */
local_match:1, /* Matched a local element */
friend_match:1; /* Matched an LPN we're friends for */
s8_t rssi;
};
/* Encoding context for Network/Transport data */
struct bt_mesh_net_tx {
struct bt_mesh_subnet *sub;
struct bt_mesh_msg_ctx *ctx;
u16_t src;
u8_t xmit;
u8_t friend_cred:1,
aszmic:1,
aid:6;
};
extern struct bt_mesh_net bt_mesh;
#define BT_MESH_NET_IVI_TX (bt_mesh.iv_index - bt_mesh.iv_update)
#define BT_MESH_NET_IVI_RX(rx) (bt_mesh.iv_index - (rx)->old_iv)
#define BT_MESH_NET_HDR_LEN 9
int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys,
const u8_t key[16]);
int bt_mesh_net_create(u16_t idx, u8_t flags, const u8_t key[16],
u32_t iv_index);
u8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub);
bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, u8_t new_kr, bool new_key);
void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub);
int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub);
void bt_mesh_rpl_reset(void);
bool bt_mesh_net_iv_update(u32_t iv_index, bool iv_update);
void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub);
struct bt_mesh_subnet *bt_mesh_subnet_get(u16_t net_idx);
struct bt_mesh_subnet *bt_mesh_subnet_find(const u8_t net_id[8], u8_t flags,
u32_t iv_index, const u8_t auth[8],
bool *new_key);
int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct net_buf_simple *buf,
bool proxy);
int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf,
const struct bt_mesh_send_cb *cb, void *cb_data);
int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct net_buf *buf,
bool new_key, const struct bt_mesh_send_cb *cb,
void *cb_data);
int bt_mesh_net_decode(struct net_buf_simple *data, enum bt_mesh_net_if net_if,
struct bt_mesh_net_rx *rx, struct net_buf_simple *buf);
void bt_mesh_net_recv(struct net_buf_simple *data, s8_t rssi,
enum bt_mesh_net_if net_if);
void bt_mesh_net_init(void);
/* Friendship Credential Management */
struct friend_cred {
u16_t net_idx;
u16_t addr;
u16_t lpn_counter;
u16_t frnd_counter;
struct {
u8_t nid; /* NID */
u8_t enc[16]; /* EncKey */
u8_t privacy[16]; /* PrivacyKey */
} cred[2];
};
int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv);
int friend_cred_set(struct friend_cred *cred, u8_t idx, const u8_t net_key[16]);
void friend_cred_refresh(u16_t net_idx);
int friend_cred_update(struct bt_mesh_subnet *sub);
struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr,
u16_t lpn_counter, u16_t frnd_counter);
void friend_cred_clear(struct friend_cred *cred);
int friend_cred_del(u16_t net_idx, u16_t addr);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,22 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
void bt_mesh_pb_adv_recv(struct net_buf_simple *buf);
bool bt_prov_active(void);
int bt_mesh_pb_gatt_open(struct bt_conn *conn);
int bt_mesh_pb_gatt_close(struct bt_conn *conn);
int bt_mesh_pb_gatt_recv(struct bt_conn *conn, struct net_buf_simple *buf);
const u8_t *bt_mesh_prov_get_uuid(void);
int bt_mesh_prov_init(const struct bt_mesh_prov *prov);
void bt_mesh_prov_complete(u16_t net_idx, u16_t addr);
void bt_mesh_prov_reset(void);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,37 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define BT_MESH_PROXY_NET_PDU 0x00
#define BT_MESH_PROXY_BEACON 0x01
#define BT_MESH_PROXY_CONFIG 0x02
#define BT_MESH_PROXY_PROV 0x03
int bt_mesh_proxy_send(struct bt_conn *conn, u8_t type,
struct net_buf_simple *msg);
int bt_mesh_proxy_prov_enable(void);
int bt_mesh_proxy_prov_disable(void);
int bt_mesh_proxy_gatt_enable(void);
int bt_mesh_proxy_gatt_disable(void);
void bt_mesh_proxy_gatt_disconnect(void);
void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub);
struct net_buf_simple *bt_mesh_proxy_get_buf(void);
s32_t bt_mesh_proxy_adv_start(void);
void bt_mesh_proxy_adv_stop(void);
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub);
void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub);
bool bt_mesh_proxy_relay(struct net_buf_simple *buf, u16_t dst);
void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, u16_t addr);
int bt_mesh_proxy_init(void);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,22 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include <bluetooth/mesh.h>
#include "common/log.h"
#include "mesh.h"
#include "test.h"
int bt_mesh_test(void)
{
return 0;
}

View file

@ -0,0 +1,16 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#if defined(CONFIG_BT_MESH_SELF_TEST)
int bt_mesh_test(void);
#else
static inline int bt_mesh_test(void)
{
return 0;
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,97 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#define TRANS_SEQ_AUTH_NVAL 0xffffffffffffffff
#define BT_MESH_TX_SEG_COUNT (CONFIG_BT_MESH_ADV_BUF_COUNT - 3)
#define BT_MESH_TX_SDU_MAX (BT_MESH_TX_SEG_COUNT * 12)
#define TRANS_CTL_OP_MASK ((u8_t)BIT_MASK(7))
#define TRANS_CTL_OP(data) ((data)[0] & TRANS_CTL_OP_MASK)
#define TRANS_CTL_HDR(op, seg) ((op & TRANS_CTL_OP_MASK) | (seg << 7))
#define TRANS_CTL_OP_ACK 0x00
#define TRANS_CTL_OP_FRIEND_POLL 0x01
#define TRANS_CTL_OP_FRIEND_UPDATE 0x02
#define TRANS_CTL_OP_FRIEND_REQ 0x03
#define TRANS_CTL_OP_FRIEND_OFFER 0x04
#define TRANS_CTL_OP_FRIEND_CLEAR 0x05
#define TRANS_CTL_OP_FRIEND_CLEAR_CFM 0x06
#define TRANS_CTL_OP_FRIEND_SUB_ADD 0x07
#define TRANS_CTL_OP_FRIEND_SUB_REM 0x08
#define TRANS_CTL_OP_FRIEND_SUB_CFM 0x09
#define TRANS_CTL_OP_HEARTBEAT 0x0a
struct bt_mesh_ctl_friend_poll {
u8_t fsn;
} __packed;
struct bt_mesh_ctl_friend_update {
u8_t flags;
u32_t iv_index;
u8_t md;
} __packed;
struct bt_mesh_ctl_friend_req {
u8_t criteria;
u8_t recv_delay;
u8_t poll_to[3];
u16_t prev_addr;
u8_t num_elem;
u16_t lpn_counter;
} __packed;
struct bt_mesh_ctl_friend_offer {
u8_t recv_win;
u8_t queue_size;
u8_t sub_list_size;
s8_t rssi;
u16_t frnd_counter;
} __packed;
struct bt_mesh_ctl_friend_clear {
u16_t lpn_addr;
u16_t lpn_counter;
} __packed;
struct bt_mesh_ctl_friend_clear_confirm {
u16_t lpn_addr;
u16_t lpn_counter;
} __packed;
#define BT_MESH_FRIEND_SUB_MIN_LEN (1 + 2)
struct bt_mesh_ctl_friend_sub {
u8_t xact;
u16_t addr_list[5];
} __packed;
struct bt_mesh_ctl_friend_sub_confirm {
u8_t xact;
} __packed;
void bt_mesh_set_hb_sub_dst(u16_t addr);
struct bt_mesh_app_key *bt_mesh_app_key_find(u16_t app_idx);
bool bt_mesh_tx_in_progress(void);
void bt_mesh_rx_reset(void);
void bt_mesh_tx_reset(void);
int bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data,
size_t data_len, u64_t *seq_auth,
const struct bt_mesh_send_cb *cb, void *cb_data);
int bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct net_buf_simple *msg,
const struct bt_mesh_send_cb *cb, void *cb_data);
int bt_mesh_trans_recv(struct net_buf_simple *buf, struct bt_mesh_net_rx *rx);
void bt_mesh_trans_init(void);
void bt_mesh_rpl_clear(void);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,221 @@
/** @file
* @brief Internal APIs for Bluetooth connection handling.
*/
/*
* Copyright (c) 2015 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
typedef enum __packed {
BT_CONN_DISCONNECTED,
BT_CONN_CONNECT_SCAN,
BT_CONN_CONNECT,
BT_CONN_CONNECTED,
BT_CONN_DISCONNECT,
} bt_conn_state_t;
/* bt_conn flags: the flags defined here represent connection parameters */
enum {
BT_CONN_AUTO_CONNECT,
BT_CONN_BR_LEGACY_SECURE, /* 16 digits legacy PIN tracker */
BT_CONN_USER, /* user I/O when pairing */
BT_CONN_BR_PAIRING, /* BR connection in pairing context */
BT_CONN_BR_NOBOND, /* SSP no bond pairing tracker */
BT_CONN_BR_PAIRING_INITIATOR, /* local host starts authentication */
BT_CONN_CLEANUP, /* Disconnected, pending cleanup */
BT_CONN_AUTO_PHY_UPDATE, /* Auto-update PHY */
BT_CONN_AUTO_DATA_LEN, /* Auto data len change in progress */
/* Total number of flags - must be at the end of the enum */
BT_CONN_NUM_FLAGS,
};
struct bt_conn_le {
bt_addr_le_t dst;
bt_addr_le_t init_addr;
bt_addr_le_t resp_addr;
u16_t interval;
u16_t interval_min;
u16_t interval_max;
u16_t latency;
u16_t timeout;
u8_t features[8];
struct bt_keys *keys;
/* Delayed work for connection update and timeout handling */
struct k_delayed_work update_work;
};
#if defined(CONFIG_BT_BREDR)
/* For now reserve space for 2 pages of LMP remote features */
#define LMP_MAX_PAGES 2
struct bt_conn_br {
bt_addr_t dst;
u8_t remote_io_capa;
u8_t remote_auth;
u8_t pairing_method;
/* remote LMP features pages per 8 bytes each */
u8_t features[LMP_MAX_PAGES][8];
struct bt_keys_link_key *link_key;
};
struct bt_conn_sco {
/* Reference to ACL Connection */
struct bt_conn *acl;
u16_t pkt_type;
};
#endif
typedef void (*bt_conn_tx_cb_t)(struct bt_conn *conn);
struct bt_conn_tx {
sys_snode_t node;
bt_conn_tx_cb_t cb;
};
struct bt_conn {
u16_t handle;
u8_t type;
u8_t role;
ATOMIC_DEFINE(flags, BT_CONN_NUM_FLAGS);
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
bt_security_t sec_level;
bt_security_t required_sec_level;
u8_t encrypt;
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
/* Connection error or reason for disconnect */
u8_t err;
bt_conn_state_t state;
u16_t rx_len;
struct net_buf *rx;
/* Sent but not acknowledged TX packets */
sys_slist_t tx_pending;
/* Acknowledged but not yet notified TX packets */
struct k_fifo tx_notify;
/* Queue for outgoing ACL data */
struct k_fifo tx_queue;
/* Active L2CAP channels */
sys_slist_t channels;
atomic_t ref;
union {
struct bt_conn_le le;
#if defined(CONFIG_BT_BREDR)
struct bt_conn_br br;
struct bt_conn_sco sco;
#endif
};
};
/* Process incoming data for a connection */
void bt_conn_recv(struct bt_conn *conn, struct net_buf *buf, u8_t flags);
/* Send data over a connection */
int bt_conn_send_cb(struct bt_conn *conn, struct net_buf *buf,
bt_conn_tx_cb_t cb);
static inline int bt_conn_send(struct bt_conn *conn, struct net_buf *buf)
{
return bt_conn_send_cb(conn, buf, NULL);
}
/* Add a new LE connection */
struct bt_conn *bt_conn_add_le(const bt_addr_le_t *peer);
/* Add a new BR/EDR connection */
struct bt_conn *bt_conn_add_br(const bt_addr_t *peer);
/* Add a new SCO connection */
struct bt_conn *bt_conn_add_sco(const bt_addr_t *peer, int link_type);
/* Cleanup SCO references */
void bt_sco_cleanup(struct bt_conn *sco_conn);
/* Look up an existing sco connection by BT address */
struct bt_conn *bt_conn_lookup_addr_sco(const bt_addr_t *peer);
/* Look up an existing connection by BT address */
struct bt_conn *bt_conn_lookup_addr_br(const bt_addr_t *peer);
void bt_conn_pin_code_req(struct bt_conn *conn);
u8_t bt_conn_get_io_capa(void);
u8_t bt_conn_ssp_get_auth(const struct bt_conn *conn);
void bt_conn_ssp_auth(struct bt_conn *conn, u32_t passkey);
void bt_conn_disconnect_all(void);
/* Look up an existing connection */
struct bt_conn *bt_conn_lookup_handle(u16_t handle);
/* Compare an address with bt_conn destination address */
int bt_conn_addr_le_cmp(const struct bt_conn *conn, const bt_addr_le_t *peer);
/* Helpers for identifying & looking up connections based on the the index to
* the connection list. This is useful for O(1) lookups, but can't be used
* e.g. as the handle since that's assigned to us by the controller.
*/
#define BT_CONN_ID_INVALID 0xff
u8_t bt_conn_get_id(struct bt_conn *conn);
struct bt_conn *bt_conn_lookup_id(u8_t id);
/* Look up a connection state. For BT_ADDR_LE_ANY, returns the first connection
* with the specific state
*/
struct bt_conn *bt_conn_lookup_state_le(const bt_addr_le_t *peer,
const bt_conn_state_t state);
/* Set connection object in certain state and perform action related to state */
void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state);
int bt_conn_le_conn_update(struct bt_conn *conn,
const struct bt_le_conn_param *param);
void notify_le_param_updated(struct bt_conn *conn);
bool le_param_req(struct bt_conn *conn, struct bt_le_conn_param *param);
#if defined(CONFIG_BT_SMP)
/* rand and ediv should be in BT order */
int bt_conn_le_start_encryption(struct bt_conn *conn, u64_t rand,
u16_t ediv, const u8_t *ltk, size_t len);
/* Notify higher layers that RPA was resolved */
void bt_conn_identity_resolved(struct bt_conn *conn);
#endif /* CONFIG_BT_SMP */
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
/* Notify higher layers that connection security changed */
void bt_conn_security_changed(struct bt_conn *conn);
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
/* Prepare a PDU to be sent over a connection */
struct net_buf *bt_conn_create_pdu(struct net_buf_pool *pool, size_t reserve);
/* Initialize connection management */
int bt_conn_init(void);
/* Selects based on connecton type right semaphore for ACL packets */
struct k_sem *bt_conn_get_pkts(struct bt_conn *conn);
/* k_poll related helpers for the TX thread */
int bt_conn_prepare_events(struct k_poll_event events[]);
void bt_conn_process_tx(struct bt_conn *conn);
void bt_conn_notify_tx(struct bt_conn *conn);

View file

@ -0,0 +1,160 @@
/*
* Copyright (c) 2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include <zephyr.h>
#include <misc/byteorder.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/conn.h>
#include <tinycrypt/constants.h>
#include <tinycrypt/hmac_prng.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/utils.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
#include "common/log.h"
#include "hci_core.h"
static struct tc_hmac_prng_struct prng;
static int prng_reseed(struct tc_hmac_prng_struct *h)
{
u8_t seed[32];
s64_t extra;
int ret, i;
for (i = 0; i < (sizeof(seed) / 8); i++) {
struct bt_hci_rp_le_rand *rp;
struct net_buf *rsp;
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
if (ret) {
return ret;
}
rp = (void *)rsp->data;
memcpy(&seed[i * 8], rp->rand, 8);
net_buf_unref(rsp);
}
extra = k_uptime_get();
ret = tc_hmac_prng_reseed(h, seed, sizeof(seed), (u8_t *)&extra,
sizeof(extra));
if (ret == TC_CRYPTO_FAIL) {
BT_ERR("Failed to re-seed PRNG");
return -EIO;
}
return 0;
}
int prng_init(void)
{
struct bt_hci_rp_le_rand *rp;
struct net_buf *rsp;
int ret;
/* Check first that HCI_LE_Rand is supported */
if (!(bt_dev.supported_commands[27] & BIT(7))) {
return -ENOTSUP;
}
ret = bt_hci_cmd_send_sync(BT_HCI_OP_LE_RAND, NULL, &rsp);
if (ret) {
return ret;
}
rp = (void *)rsp->data;
ret = tc_hmac_prng_init(&prng, rp->rand, sizeof(rp->rand));
net_buf_unref(rsp);
if (ret == TC_CRYPTO_FAIL) {
BT_ERR("Failed to initialize PRNG");
return -EIO;
}
/* re-seed is needed after init */
return prng_reseed(&prng);
}
int bt_rand(void *buf, size_t len)
{
int ret;
ret = tc_hmac_prng_generate(buf, len, &prng);
if (ret == TC_HMAC_PRNG_RESEED_REQ) {
ret = prng_reseed(&prng);
if (ret) {
return ret;
}
ret = tc_hmac_prng_generate(buf, len, &prng);
}
if (ret == TC_CRYPTO_SUCCESS) {
return 0;
}
return -EIO;
}
int bt_encrypt_le(const u8_t key[16], const u8_t plaintext[16],
u8_t enc_data[16])
{
struct tc_aes_key_sched_struct s;
u8_t tmp[16];
BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));
sys_memcpy_swap(tmp, key, 16);
if (tc_aes128_set_encrypt_key(&s, tmp) == TC_CRYPTO_FAIL) {
return -EINVAL;
}
sys_memcpy_swap(tmp, plaintext, 16);
if (tc_aes_encrypt(enc_data, tmp, &s) == TC_CRYPTO_FAIL) {
return -EINVAL;
}
sys_mem_swap(enc_data, 16);
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
return 0;
}
int bt_encrypt_be(const u8_t key[16], const u8_t plaintext[16],
u8_t enc_data[16])
{
struct tc_aes_key_sched_struct s;
BT_DBG("key %s plaintext %s", bt_hex(key, 16), bt_hex(plaintext, 16));
if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) {
return -EINVAL;
}
if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) {
return -EINVAL;
}
BT_DBG("enc_data %s", bt_hex(enc_data, 16));
return 0;
}

View file

@ -0,0 +1,8 @@
/*
* Copyright (c) 2016-2017 Nordic Semiconductor ASA
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
int prng_init(void);

View file

@ -0,0 +1,63 @@
/* ecc.h - ECDH helpers */
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/* @brief Container for public key callback */
struct bt_pub_key_cb {
/** @brief Callback type for Public Key generation.
*
* Used to notify of the local public key or that the local key is not
* available (either because of a failure to read it or because it is
* being regenerated).
*
* @param key The local public key, or NULL in case of no key.
*/
void (*func)(const u8_t key[64]);
struct bt_pub_key_cb *_next;
};
/* @brief Generate a new Public Key.
*
* Generate a new ECC Public Key. The callback will persist even after the
* key has been generated, and will be used to notify of new generation
* processes (NULL as key).
*
* @param cb Callback to notify the new key, or NULL to request an update
* without registering any new callback.
*
* @return Zero on success or negative error code otherwise
*/
int bt_pub_key_gen(struct bt_pub_key_cb *cb);
/* @brief Get the current Public Key.
*
* Get the current ECC Public Key.
*
* @return Current key, or NULL if not available.
*/
const u8_t *bt_pub_key_get(void);
/* @typedef bt_dh_key_cb_t
* @brief Callback type for DH Key calculation.
*
* Used to notify of the calculated DH Key.
*
* @param key The DH Key, or NULL in case of failure.
*/
typedef void (*bt_dh_key_cb_t)(const u8_t key[32]);
/* @brief Calculate a DH Key from a remote Public Key.
*
* Calculate a DH Key from the remote Public Key.
*
* @param remote_pk Remote Public Key.
* @param cb Callback to notify the calculated key.
*
* @return Zero on success or negative error code otherwise
*/
int bt_dh_key_gen(const u8_t remote_pk[64], bt_dh_key_cb_t cb);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,23 @@
/** @file
* @brief Internal API for Generic Attribute Profile handling.
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
void bt_gatt_init(void);
void bt_gatt_connected(struct bt_conn *conn);
void bt_gatt_disconnected(struct bt_conn *conn);
#if defined(CONFIG_BT_GATT_CLIENT)
void bt_gatt_notification(struct bt_conn *conn, u16_t handle,
const void *data, u16_t length);
#else
static inline void bt_gatt_notification(struct bt_conn *conn, u16_t handle,
const void *data, u16_t length)
{
}
#endif /* CONFIG_BT_GATT_CLIENT */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,192 @@
/* hci_core.h - Bluetooth HCI core access */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/* LL connection parameters */
#define LE_CONN_LATENCY 0x0000
#define LE_CONN_TIMEOUT 0x002a
#if defined(CONFIG_BT_BREDR)
#define LMP_FEAT_PAGES_COUNT 3
#else
#define LMP_FEAT_PAGES_COUNT 1
#endif
/* SCO settings */
#define BT_VOICE_CVSD_16BIT 0x0060
/* k_poll event tags */
enum {
BT_EVENT_CMD_TX,
BT_EVENT_CONN_TX_NOTIFY,
BT_EVENT_CONN_TX_QUEUE,
};
/* bt_dev flags: the flags defined here represent BT controller state */
enum {
BT_DEV_ENABLE,
BT_DEV_READY,
BT_DEV_ID_STATIC_RANDOM,
BT_DEV_HAS_PUB_KEY,
BT_DEV_PUB_KEY_BUSY,
BT_DEV_ADVERTISING,
BT_DEV_KEEP_ADVERTISING,
BT_DEV_SCANNING,
BT_DEV_EXPLICIT_SCAN,
BT_DEV_ACTIVE_SCAN,
BT_DEV_SCAN_FILTER_DUP,
BT_DEV_RPA_VALID,
BT_DEV_ID_PENDING,
#if defined(CONFIG_BT_BREDR)
BT_DEV_ISCAN,
BT_DEV_PSCAN,
BT_DEV_INQUIRY,
#endif /* CONFIG_BT_BREDR */
/* Total number of flags - must be at the end of the enum */
BT_DEV_NUM_FLAGS,
};
struct bt_dev_le {
/* LE features */
u8_t features[8];
/* LE states */
u64_t states;
#if defined(CONFIG_BT_CONN)
/* Controller buffer information */
u16_t mtu;
struct k_sem pkts;
#endif /* CONFIG_BT_CONN */
#if defined(CONFIG_BT_SMP)
/* Size of the the controller resolving list */
u8_t rl_size;
/* Number of entries in the resolving list. rl_entries > rl_size
* means that host-side resolving is used.
*/
u8_t rl_entries;
#endif /* CONFIG_BT_SMP */
};
#if defined(CONFIG_BT_BREDR)
struct bt_dev_br {
/* Max controller's acceptable ACL packet length */
u16_t mtu;
struct k_sem pkts;
u16_t esco_pkt_type;
};
#endif
/* The theoretical max for these is 8 and 64, but there's no point
* in allocating the full memory if we only support a small subset.
* These values must be updated whenever the host implementation is
* extended beyond the current values.
*/
#define BT_DEV_VS_FEAT_MAX 1
#define BT_DEV_VS_CMDS_MAX 2
/* State tracking for the local Bluetooth controller */
struct bt_dev {
/* Local Identity Address */
bt_addr_le_t id_addr;
/* Current local Random Address */
bt_addr_le_t random_addr;
/* Controller version & manufacturer information */
u8_t hci_version;
u8_t lmp_version;
u16_t hci_revision;
u16_t lmp_subversion;
u16_t manufacturer;
/* LMP features (pages 0, 1, 2) */
u8_t features[LMP_FEAT_PAGES_COUNT][8];
/* Supported commands */
u8_t supported_commands[64];
#if defined(CONFIG_BT_HCI_VS_EXT)
/* Vendor HCI support */
u8_t vs_features[BT_DEV_VS_FEAT_MAX];
u8_t vs_commands[BT_DEV_VS_CMDS_MAX];
#endif
struct k_work init;
ATOMIC_DEFINE(flags, BT_DEV_NUM_FLAGS);
/* LE controller specific features */
struct bt_dev_le le;
#if defined(CONFIG_BT_BREDR)
/* BR/EDR controller specific features */
struct bt_dev_br br;
#endif
/* Number of commands controller can accept */
struct k_sem ncmd_sem;
/* Last sent HCI command */
struct net_buf *sent_cmd;
#if !defined(CONFIG_BT_RECV_IS_RX_THREAD)
/* Queue for incoming HCI events & ACL data */
struct k_fifo rx_queue;
#endif
/* Queue for high priority HCI events which may unlock waiters
* in other threads. Such events include Number of Completed
* Packets, as well as the Command Complete/Status events.
*/
struct k_fifo rx_prio_queue;
/* Queue for outgoing HCI commands */
struct k_fifo cmd_tx_queue;
/* Registered HCI driver */
const struct bt_hci_driver *drv;
#if defined(CONFIG_BT_PRIVACY)
/* Local Identity Resolving Key */
u8_t irk[16];
/* Work used for RPA rotation */
struct k_delayed_work rpa_update;
#endif
};
extern struct bt_dev bt_dev;
extern const struct bt_storage *bt_storage;
#if defined(CONFIG_BT_SMP) || defined(CONFIG_BT_BREDR)
extern const struct bt_conn_auth_cb *bt_auth;
#endif /* CONFIG_BT_SMP || CONFIG_BT_BREDR */
bool bt_le_conn_params_valid(const struct bt_le_conn_param *param);
struct net_buf *bt_hci_cmd_create(u16_t opcode, u8_t param_len);
int bt_hci_cmd_send(u16_t opcode, struct net_buf *buf);
int bt_hci_cmd_send_sync(u16_t opcode, struct net_buf *buf,
struct net_buf **rsp);
int bt_le_scan_update(bool fast_scan);
bool bt_addr_le_is_bonded(const bt_addr_le_t *addr);
int bt_send(struct net_buf *buf);
u16_t bt_hci_get_cmd_opcode(struct net_buf *buf);
/* Don't require everyone to include keys.h */
struct bt_keys;
int bt_id_add(struct bt_keys *keys);
int bt_id_del(struct bt_keys *keys);

View file

@ -0,0 +1,324 @@
/**
* @file hci_ecc.c
* HCI ECC emulation
*/
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <atomic.h>
#include <misc/stack.h>
#include <misc/byteorder.h>
#include <tinycrypt/constants.h>
#include <tinycrypt/utils.h>
#include <tinycrypt/ecc.h>
#include <tinycrypt/ecc_dh.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_driver.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
#include "common/log.h"
#include "hci_ecc.h"
#ifdef CONFIG_BT_HCI_RAW
#include <bluetooth/hci_raw.h>
#include "hci_raw_internal.h"
#else
#include "hci_core.h"
#endif
static struct k_thread ecc_thread_data;
static BT_STACK_NOINIT(ecc_thread_stack, 1024);
/* based on Core Specification 4.2 Vol 3. Part H 2.3.5.6.1 */
static const u32_t debug_private_key[8] = {
0xcd3c1abd, 0x5899b8a6, 0xeb40b799, 0x4aff607b, 0xd2103f50, 0x74c9b3e3,
0xa3c55f38, 0x3f49f6d4
};
#if defined(CONFIG_BT_USE_DEBUG_KEYS)
static const u8_t debug_public_key[64] = {
0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc, 0xdb, 0xfd, 0xf4, 0xac,
0x11, 0x91, 0xf4, 0xef, 0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
0x2c, 0xbe, 0x97, 0xf2, 0xd2, 0x03, 0xb0, 0x20, 0x8b, 0xd2, 0x89, 0x15,
0xd0, 0x8e, 0x1c, 0x74, 0x24, 0x30, 0xed, 0x8f, 0xc2, 0x45, 0x63, 0x76,
0x5c, 0x15, 0x52, 0x5a, 0xbf, 0x9a, 0x32, 0x63, 0x6d, 0xeb, 0x2a, 0x65,
0x49, 0x9c, 0x80, 0xdc
};
#endif
enum {
PENDING_PUB_KEY,
PENDING_DHKEY,
/* Total number of flags - must be at the end of the enum */
NUM_FLAGS,
};
static ATOMIC_DEFINE(flags, NUM_FLAGS);
static K_SEM_DEFINE(cmd_sem, 0, 1);
static struct {
u8_t private_key[32];
union {
u8_t pk[64];
u8_t dhkey[32];
};
} ecc;
static void send_cmd_status(u16_t opcode, u8_t status)
{
struct bt_hci_evt_cmd_status *evt;
struct bt_hci_evt_hdr *hdr;
struct net_buf *buf;
BT_DBG("opcode %x status %x", opcode, status);
buf = bt_buf_get_cmd_complete(K_FOREVER);
bt_buf_set_type(buf, BT_BUF_EVT);
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->evt = BT_HCI_EVT_CMD_STATUS;
hdr->len = sizeof(*evt);
evt = net_buf_add(buf, sizeof(*evt));
evt->ncmd = 1;
evt->opcode = sys_cpu_to_le16(opcode);
evt->status = status;
bt_recv_prio(buf);
}
static u8_t generate_keys(void)
{
#if !defined(CONFIG_BT_USE_DEBUG_KEYS)
do {
int rc;
rc = uECC_make_key(ecc.pk, ecc.private_key, &curve_secp256r1);
if (rc == TC_CRYPTO_FAIL) {
BT_ERR("Failed to create ECC public/private pair");
return BT_HCI_ERR_UNSPECIFIED;
}
/* make sure generated key isn't debug key */
} while (memcmp(ecc.private_key, debug_private_key, 32) == 0);
#else
memcpy(&ecc.pk, debug_public_key, 64);
memcpy(ecc.private_key, debug_private_key, 32);
#endif
return 0;
}
static void emulate_le_p256_public_key_cmd(void)
{
struct bt_hci_evt_le_p256_public_key_complete *evt;
struct bt_hci_evt_le_meta_event *meta;
struct bt_hci_evt_hdr *hdr;
struct net_buf *buf;
u8_t status;
BT_DBG("");
status = generate_keys();
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->evt = BT_HCI_EVT_LE_META_EVENT;
hdr->len = sizeof(*meta) + sizeof(*evt);
meta = net_buf_add(buf, sizeof(*meta));
meta->subevent = BT_HCI_EVT_LE_P256_PUBLIC_KEY_COMPLETE;
evt = net_buf_add(buf, sizeof(*evt));
evt->status = status;
if (status) {
memset(evt->key, 0, sizeof(evt->key));
} else {
/* Convert X and Y coordinates from big-endian (provided
* by crypto API) to little endian HCI.
*/
sys_memcpy_swap(evt->key, ecc.pk, 32);
sys_memcpy_swap(&evt->key[32], &ecc.pk[32], 32);
}
atomic_clear_bit(flags, PENDING_PUB_KEY);
bt_recv(buf);
}
static void emulate_le_generate_dhkey(void)
{
struct bt_hci_evt_le_generate_dhkey_complete *evt;
struct bt_hci_evt_le_meta_event *meta;
struct bt_hci_evt_hdr *hdr;
struct net_buf *buf;
int ret;
ret = uECC_valid_public_key(ecc.pk, &curve_secp256r1);
if (ret < 0) {
BT_ERR("public key is not valid (ret %d)", ret);
ret = TC_CRYPTO_FAIL;
} else {
ret = uECC_shared_secret(ecc.pk, ecc.private_key, ecc.dhkey,
&curve_secp256r1);
}
buf = bt_buf_get_rx(BT_BUF_EVT, K_FOREVER);
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->evt = BT_HCI_EVT_LE_META_EVENT;
hdr->len = sizeof(*meta) + sizeof(*evt);
meta = net_buf_add(buf, sizeof(*meta));
meta->subevent = BT_HCI_EVT_LE_GENERATE_DHKEY_COMPLETE;
evt = net_buf_add(buf, sizeof(*evt));
if (ret == TC_CRYPTO_FAIL) {
evt->status = BT_HCI_ERR_UNSPECIFIED;
memset(evt->dhkey, 0, sizeof(evt->dhkey));
} else {
evt->status = 0;
/* Convert from big-endian (provided by crypto API) to
* little-endian HCI.
*/
sys_memcpy_swap(evt->dhkey, ecc.dhkey, sizeof(ecc.dhkey));
}
atomic_clear_bit(flags, PENDING_DHKEY);
bt_recv(buf);
}
static void ecc_thread(void *p1, void *p2, void *p3)
{
while (true) {
k_sem_take(&cmd_sem, K_FOREVER);
if (atomic_test_bit(flags, PENDING_PUB_KEY)) {
emulate_le_p256_public_key_cmd();
} else if (atomic_test_bit(flags, PENDING_DHKEY)) {
emulate_le_generate_dhkey();
} else {
__ASSERT(0, "Unhandled ECC command");
}
STACK_ANALYZE("ecc stack", ecc_thread_stack);
}
}
static void clear_ecc_events(struct net_buf *buf)
{
struct bt_hci_cp_le_set_event_mask *cmd;
cmd = (void *)buf->data + sizeof(struct bt_hci_cmd_hdr);
/*
* don't enable controller ECC events as those will be generated from
* emulation code
*/
cmd->events[0] &= ~0x80; /* LE Read Local P-256 PKey Compl */
cmd->events[1] &= ~0x01; /* LE Generate DHKey Compl Event */
}
static void le_gen_dhkey(struct net_buf *buf)
{
struct bt_hci_cp_le_generate_dhkey *cmd;
u8_t status;
if (atomic_test_bit(flags, PENDING_PUB_KEY)) {
status = BT_HCI_ERR_CMD_DISALLOWED;
goto send_status;
}
if (buf->len < sizeof(struct bt_hci_cp_le_generate_dhkey)) {
status = BT_HCI_ERR_INVALID_PARAM;
goto send_status;
}
if (atomic_test_and_set_bit(flags, PENDING_DHKEY)) {
status = BT_HCI_ERR_CMD_DISALLOWED;
goto send_status;
}
cmd = (void *)buf->data;
/* Convert X and Y coordinates from little-endian HCI to
* big-endian (expected by the crypto API).
*/
sys_memcpy_swap(ecc.pk, cmd->key, 32);
sys_memcpy_swap(&ecc.pk[32], &cmd->key[32], 32);
k_sem_give(&cmd_sem);
status = BT_HCI_ERR_SUCCESS;
send_status:
net_buf_unref(buf);
send_cmd_status(BT_HCI_OP_LE_GENERATE_DHKEY, status);
}
static void le_p256_pub_key(struct net_buf *buf)
{
u8_t status;
net_buf_unref(buf);
if (atomic_test_bit(flags, PENDING_DHKEY)) {
status = BT_HCI_ERR_CMD_DISALLOWED;
} else if (atomic_test_and_set_bit(flags, PENDING_PUB_KEY)) {
status = BT_HCI_ERR_CMD_DISALLOWED;
} else {
k_sem_give(&cmd_sem);
status = BT_HCI_ERR_SUCCESS;
}
send_cmd_status(BT_HCI_OP_LE_P256_PUBLIC_KEY, status);
}
int bt_hci_ecc_send(struct net_buf *buf)
{
if (bt_buf_get_type(buf) == BT_BUF_CMD) {
struct bt_hci_cmd_hdr *chdr = (void *)buf->data;
switch (sys_le16_to_cpu(chdr->opcode)) {
case BT_HCI_OP_LE_P256_PUBLIC_KEY:
net_buf_pull(buf, sizeof(*chdr));
le_p256_pub_key(buf);
return 0;
case BT_HCI_OP_LE_GENERATE_DHKEY:
net_buf_pull(buf, sizeof(*chdr));
le_gen_dhkey(buf);
return 0;
case BT_HCI_OP_LE_SET_EVENT_MASK:
clear_ecc_events(buf);
break;
default:
break;
}
}
return bt_dev.drv->send(buf);
}
int default_CSPRNG(u8_t *dst, unsigned int len)
{
return !bt_rand(dst, len);
}
void bt_hci_ecc_init(void)
{
k_sem_init(&cmd_sem, 0, 1);
k_thread_create(&ecc_thread_data, ecc_thread_stack,
K_THREAD_STACK_SIZEOF(ecc_thread_stack), ecc_thread,
NULL, NULL, NULL, 41, 0, K_NO_WAIT);
}

View file

@ -0,0 +1,10 @@
/* hci_ecc.h - HCI ECC emulation */
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
void bt_hci_ecc_init(void);
int bt_hci_ecc_send(struct net_buf *buf);

View file

@ -0,0 +1,180 @@
/* keys.c - Bluetooth key handling */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <string.h>
#include <atomic.h>
#include <misc/util.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/hci.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_KEYS)
#include "common/log.h"
#include "common/rpa.h"
#include "hci_core.h"
#include "smp.h"
#include "keys.h"
static struct bt_keys key_pool[CONFIG_BT_MAX_PAIRED];
struct bt_keys *bt_keys_get_addr(const bt_addr_le_t *addr)
{
struct bt_keys *keys;
int i;
BT_DBG("%s", bt_addr_le_str(addr));
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
keys = &key_pool[i];
if (!bt_addr_le_cmp(&keys->addr, addr)) {
return keys;
}
if (!bt_addr_le_cmp(&keys->addr, BT_ADDR_LE_ANY)) {
bt_addr_le_copy(&keys->addr, addr);
BT_DBG("created %p for %s", keys, bt_addr_le_str(addr));
return keys;
}
}
BT_DBG("unable to create keys for %s", bt_addr_le_str(addr));
return NULL;
}
void bt_keys_foreach(int type, void (*func)(struct bt_keys *keys))
{
int i;
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
if ((key_pool[i].keys & type)) {
func(&key_pool[i]);
}
}
}
struct bt_keys *bt_keys_find(int type, const bt_addr_le_t *addr)
{
int i;
BT_DBG("type %d %s", type, bt_addr_le_str(addr));
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
if ((key_pool[i].keys & type) &&
!bt_addr_le_cmp(&key_pool[i].addr, addr)) {
return &key_pool[i];
}
}
return NULL;
}
struct bt_keys *bt_keys_get_type(int type, const bt_addr_le_t *addr)
{
struct bt_keys *keys;
BT_DBG("type %d %s", type, bt_addr_le_str(addr));
keys = bt_keys_find(type, addr);
if (keys) {
return keys;
}
keys = bt_keys_get_addr(addr);
if (!keys) {
return NULL;
}
bt_keys_add_type(keys, type);
return keys;
}
struct bt_keys *bt_keys_find_irk(const bt_addr_le_t *addr)
{
int i;
BT_DBG("%s", bt_addr_le_str(addr));
if (!bt_addr_le_is_rpa(addr)) {
return NULL;
}
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
if (!(key_pool[i].keys & BT_KEYS_IRK)) {
continue;
}
if (!bt_addr_cmp(&addr->a, &key_pool[i].irk.rpa)) {
BT_DBG("cached RPA %s for %s",
bt_addr_str(&key_pool[i].irk.rpa),
bt_addr_le_str(&key_pool[i].addr));
return &key_pool[i];
}
}
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
if (!(key_pool[i].keys & BT_KEYS_IRK)) {
continue;
}
if (bt_rpa_irk_matches(key_pool[i].irk.val, &addr->a)) {
BT_DBG("RPA %s matches %s",
bt_addr_str(&key_pool[i].irk.rpa),
bt_addr_le_str(&key_pool[i].addr));
bt_addr_copy(&key_pool[i].irk.rpa, &addr->a);
return &key_pool[i];
}
}
BT_DBG("No IRK for %s", bt_addr_le_str(addr));
return NULL;
}
struct bt_keys *bt_keys_find_addr(const bt_addr_le_t *addr)
{
int i;
BT_DBG("%s", bt_addr_le_str(addr));
for (i = 0; i < ARRAY_SIZE(key_pool); i++) {
if (!bt_addr_le_cmp(&key_pool[i].addr, addr)) {
return &key_pool[i];
}
}
return NULL;
}
void bt_keys_add_type(struct bt_keys *keys, int type)
{
keys->keys |= type;
}
void bt_keys_clear(struct bt_keys *keys)
{
BT_DBG("keys for %s", bt_addr_le_str(&keys->addr));
if (keys->keys & BT_KEYS_IRK) {
bt_id_del(keys);
}
memset(keys, 0, sizeof(*keys));
}
void bt_keys_clear_all(void)
{
bt_keys_foreach(BT_KEYS_ALL, bt_keys_clear);
}

View file

@ -0,0 +1,94 @@
/* keys.h - Bluetooth key handling */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
enum {
BT_KEYS_SLAVE_LTK = BIT(0),
BT_KEYS_IRK = BIT(1),
BT_KEYS_LTK = BIT(2),
BT_KEYS_LOCAL_CSRK = BIT(3),
BT_KEYS_REMOTE_CSRK = BIT(4),
BT_KEYS_LTK_P256 = BIT(5),
BT_KEYS_ALL = (BT_KEYS_SLAVE_LTK | BT_KEYS_IRK | \
BT_KEYS_LTK | BT_KEYS_LOCAL_CSRK | \
BT_KEYS_REMOTE_CSRK | BT_KEYS_LTK_P256),
};
enum {
BT_KEYS_AUTHENTICATED,
BT_KEYS_DEBUG,
BT_KEYS_ID_PENDING_ADD,
BT_KEYS_ID_PENDING_DEL,
/* Total number of flags - must be at the end of the enum */
BT_KEYS_NUM_FLAGS,
};
struct bt_ltk {
u64_t rand;
u16_t ediv;
u8_t val[16];
};
struct bt_irk {
u8_t val[16];
bt_addr_t rpa;
};
struct bt_csrk {
u8_t val[16];
u32_t cnt;
};
struct bt_keys {
bt_addr_le_t addr;
u8_t enc_size;
ATOMIC_DEFINE(flags, BT_KEYS_NUM_FLAGS);
u16_t keys;
struct bt_ltk ltk;
struct bt_irk irk;
#if defined(CONFIG_BT_SIGNING)
struct bt_csrk local_csrk;
struct bt_csrk remote_csrk;
#endif /* BT_SIGNING */
#if !defined(CONFIG_BT_SMP_SC_ONLY)
struct bt_ltk slave_ltk;
#endif /* CONFIG_BT_SMP_SC_ONLY */
};
void bt_keys_foreach(int type, void (*func)(struct bt_keys *keys));
struct bt_keys *bt_keys_get_addr(const bt_addr_le_t *addr);
struct bt_keys *bt_keys_get_type(int type, const bt_addr_le_t *addr);
struct bt_keys *bt_keys_find(int type, const bt_addr_le_t *addr);
struct bt_keys *bt_keys_find_irk(const bt_addr_le_t *addr);
struct bt_keys *bt_keys_find_addr(const bt_addr_le_t *addr);
void bt_keys_add_type(struct bt_keys *keys, int type);
void bt_keys_clear(struct bt_keys *keys);
void bt_keys_clear_all(void);
enum {
BT_LINK_KEY_AUTHENTICATED,
BT_LINK_KEY_DEBUG,
BT_LINK_KEY_SC,
/* Total number of flags - must be at the end of the enum */
BT_LINK_KEY_NUM_FLAGS,
};
struct bt_keys_link_key {
bt_addr_t addr;
ATOMIC_DEFINE(flags, BT_LINK_KEY_NUM_FLAGS);
u8_t val[16];
};
struct bt_keys_link_key *bt_keys_get_link_key(const bt_addr_t *addr);
struct bt_keys_link_key *bt_keys_find_link_key(const bt_addr_t *addr);
void bt_keys_link_key_clear(struct bt_keys_link_key *link_key);
void bt_keys_link_key_clear_addr(const bt_addr_t *addr);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,310 @@
/** @file
* @brief Internal APIs for Bluetooth L2CAP handling.
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <bluetooth/l2cap.h>
enum l2cap_conn_list_action {
BT_L2CAP_CHAN_LOOKUP,
BT_L2CAP_CHAN_DETACH,
};
#define BT_L2CAP_CID_BR_SIG 0x0001
#define BT_L2CAP_CID_ATT 0x0004
#define BT_L2CAP_CID_LE_SIG 0x0005
#define BT_L2CAP_CID_SMP 0x0006
#define BT_L2CAP_CID_BR_SMP 0x0007
#define BT_L2CAP_PSM_RFCOMM 0x0003
struct bt_l2cap_hdr {
u16_t len;
u16_t cid;
} __packed;
struct bt_l2cap_sig_hdr {
u8_t code;
u8_t ident;
u16_t len;
} __packed;
#define BT_L2CAP_REJ_NOT_UNDERSTOOD 0x0000
#define BT_L2CAP_REJ_MTU_EXCEEDED 0x0001
#define BT_L2CAP_REJ_INVALID_CID 0x0002
#define BT_L2CAP_CMD_REJECT 0x01
struct bt_l2cap_cmd_reject {
u16_t reason;
u8_t data[0];
} __packed;
struct bt_l2cap_cmd_reject_cid_data {
u16_t scid;
u16_t dcid;
} __packed;
#define BT_L2CAP_CONN_REQ 0x02
struct bt_l2cap_conn_req {
u16_t psm;
u16_t scid;
} __packed;
/* command statuses in reposnse */
#define BT_L2CAP_CS_NO_INFO 0x0000
#define BT_L2CAP_CS_AUTHEN_PEND 0x0001
/* valid results in conn response on BR/EDR */
#define BT_L2CAP_BR_SUCCESS 0x0000
#define BT_L2CAP_BR_PENDING 0x0001
#define BT_L2CAP_BR_ERR_PSM_NOT_SUPP 0x0002
#define BT_L2CAP_BR_ERR_SEC_BLOCK 0x0003
#define BT_L2CAP_BR_ERR_NO_RESOURCES 0x0004
#define BT_L2CAP_BR_ERR_INVALID_SCID 0x0006
#define BT_L2CAP_BR_ERR_SCID_IN_USE 0x0007
#define BT_L2CAP_CONN_RSP 0x03
struct bt_l2cap_conn_rsp {
u16_t dcid;
u16_t scid;
u16_t result;
u16_t status;
} __packed;
#define BT_L2CAP_CONF_SUCCESS 0x0000
#define BT_L2CAP_CONF_UNACCEPT 0x0001
#define BT_L2CAP_CONF_REJECT 0x0002
#define BT_L2CAP_CONF_REQ 0x04
struct bt_l2cap_conf_req {
u16_t dcid;
u16_t flags;
u8_t data[0];
} __packed;
#define BT_L2CAP_CONF_RSP 0x05
struct bt_l2cap_conf_rsp {
u16_t scid;
u16_t flags;
u16_t result;
u8_t data[0];
} __packed;
/* Option type used by MTU config request data */
#define BT_L2CAP_CONF_OPT_MTU 0x01
/* Options bits selecting most significant bit (hint) in type field */
#define BT_L2CAP_CONF_HINT 0x80
#define BT_L2CAP_CONF_MASK 0x7f
struct bt_l2cap_conf_opt {
u8_t type;
u8_t len;
u8_t data[0];
} __packed;
#define BT_L2CAP_DISCONN_REQ 0x06
struct bt_l2cap_disconn_req {
u16_t dcid;
u16_t scid;
} __packed;
#define BT_L2CAP_DISCONN_RSP 0x07
struct bt_l2cap_disconn_rsp {
u16_t dcid;
u16_t scid;
} __packed;
#define BT_L2CAP_INFO_FEAT_MASK 0x0002
#define BT_L2CAP_INFO_FIXED_CHAN 0x0003
#define BT_L2CAP_INFO_REQ 0x0a
struct bt_l2cap_info_req {
u16_t type;
} __packed;
/* info result */
#define BT_L2CAP_INFO_SUCCESS 0x0000
#define BT_L2CAP_INFO_NOTSUPP 0x0001
#define BT_L2CAP_INFO_RSP 0x0b
struct bt_l2cap_info_rsp {
u16_t type;
u16_t result;
u8_t data[0];
} __packed;
#define BT_L2CAP_CONN_PARAM_REQ 0x12
struct bt_l2cap_conn_param_req {
u16_t min_interval;
u16_t max_interval;
u16_t latency;
u16_t timeout;
} __packed;
#define BT_L2CAP_CONN_PARAM_ACCEPTED 0x0000
#define BT_L2CAP_CONN_PARAM_REJECTED 0x0001
#define BT_L2CAP_CONN_PARAM_RSP 0x13
struct bt_l2cap_conn_param_rsp {
u16_t result;
} __packed;
#define BT_L2CAP_LE_CONN_REQ 0x14
struct bt_l2cap_le_conn_req {
u16_t psm;
u16_t scid;
u16_t mtu;
u16_t mps;
u16_t credits;
} __packed;
#define BT_L2CAP_SUCCESS 0x0000
#define BT_L2CAP_PENDING 0x0001
#define BT_L2CAP_ERR_PSM_NOT_SUPP 0x0002
#define BT_L2CAP_ERR_SEC_BLOCK 0x0003
#define BT_L2CAP_ERR_NO_RESOURCES 0x0004
#define BT_L2CAP_ERR_AUTHENTICATION 0x0005
#define BT_L2CAP_ERR_AUTHORIZATION 0x0006
#define BT_L2CAP_ERR_KEY_SIZE 0x0007
#define BT_L2CAP_ERR_ENCRYPTION 0x0008
#define BT_L2CAP_ERR_INVALID_SCID 0x0009
#define BT_L2CAP_ERR_SCID_IN_USE 0x000A
#define BT_L2CAP_LE_CONN_RSP 0x15
struct bt_l2cap_le_conn_rsp {
u16_t dcid;
u16_t mtu;
u16_t mps;
u16_t credits;
u16_t result;
};
#define BT_L2CAP_LE_CREDITS 0x16
struct bt_l2cap_le_credits {
u16_t cid;
u16_t credits;
} __packed;
#define BT_L2CAP_SDU_HDR_LEN 2
#if defined(CONFIG_BT_HCI_ACL_FLOW_CONTROL)
#define BT_L2CAP_RX_MTU CONFIG_BT_L2CAP_RX_MTU
#else
#define BT_L2CAP_RX_MTU (CONFIG_BT_RX_BUF_LEN - \
BT_HCI_ACL_HDR_SIZE - BT_L2CAP_HDR_SIZE)
#endif
struct bt_l2cap_fixed_chan {
u16_t cid;
int (*accept)(struct bt_conn *conn, struct bt_l2cap_chan **chan);
sys_snode_t node;
};
/* Register a fixed L2CAP channel for L2CAP */
void bt_l2cap_le_fixed_chan_register(struct bt_l2cap_fixed_chan *chan);
/* Notify L2CAP channels of a new connection */
void bt_l2cap_connected(struct bt_conn *conn);
/* Notify L2CAP channels of a disconnect event */
void bt_l2cap_disconnected(struct bt_conn *conn);
/* Add channel to the connection */
void bt_l2cap_chan_add(struct bt_conn *conn, struct bt_l2cap_chan *chan,
bt_l2cap_chan_destroy_t destroy);
/* Remove channel from the connection */
void bt_l2cap_chan_remove(struct bt_conn *conn, struct bt_l2cap_chan *chan);
/* Delete channel */
void bt_l2cap_chan_del(struct bt_l2cap_chan *chan);
const char *bt_l2cap_chan_state_str(bt_l2cap_chan_state_t state);
#if defined(CONFIG_BT_DEBUG_L2CAP)
void bt_l2cap_chan_set_state_debug(struct bt_l2cap_chan *chan,
bt_l2cap_chan_state_t state,
const char *func, int line);
#define bt_l2cap_chan_set_state(_chan, _state) \
bt_l2cap_chan_set_state_debug(_chan, _state, __func__, __LINE__)
#else
void bt_l2cap_chan_set_state(struct bt_l2cap_chan *chan,
bt_l2cap_chan_state_t state);
#endif /* CONFIG_BT_DEBUG_L2CAP */
/*
* Notify L2CAP channels of a change in encryption state passing additionally
* HCI status of performed security procedure.
*/
void bt_l2cap_encrypt_change(struct bt_conn *conn, u8_t hci_status);
/* Prepare an L2CAP PDU to be sent over a connection */
struct net_buf *bt_l2cap_create_pdu(struct net_buf_pool *pool, size_t reserve);
/* Prepare a L2CAP Response PDU to be sent over a connection */
struct net_buf *bt_l2cap_create_rsp(struct net_buf *buf, size_t reserve);
/* Send L2CAP PDU over a connection */
void bt_l2cap_send_cb(struct bt_conn *conn, u16_t cid, struct net_buf *buf,
bt_conn_tx_cb_t cb);
static inline void bt_l2cap_send(struct bt_conn *conn, u16_t cid,
struct net_buf *buf)
{
bt_l2cap_send_cb(conn, cid, buf, NULL);
}
/* Receive a new L2CAP PDU from a connection */
void bt_l2cap_recv(struct bt_conn *conn, struct net_buf *buf);
/* Perform connection parameter update request */
int bt_l2cap_update_conn_param(struct bt_conn *conn,
const struct bt_le_conn_param *param);
/* Initialize L2CAP and supported channels */
void bt_l2cap_init(void);
/* Lookup channel by Transmission CID */
struct bt_l2cap_chan *bt_l2cap_le_lookup_tx_cid(struct bt_conn *conn,
u16_t cid);
/* Lookup channel by Receiver CID */
struct bt_l2cap_chan *bt_l2cap_le_lookup_rx_cid(struct bt_conn *conn,
u16_t cid);
/* Initialize BR/EDR L2CAP signal layer */
void bt_l2cap_br_init(void);
/* Register fixed channel */
void bt_l2cap_br_fixed_chan_register(struct bt_l2cap_fixed_chan *chan);
/* Notify BR/EDR L2CAP channels about established new ACL connection */
void bt_l2cap_br_connected(struct bt_conn *conn);
/* Lookup BR/EDR L2CAP channel by Receiver CID */
struct bt_l2cap_chan *bt_l2cap_br_lookup_rx_cid(struct bt_conn *conn,
u16_t cid);
/* Disconnects dynamic channel */
int bt_l2cap_br_chan_disconnect(struct bt_l2cap_chan *chan);
/* Make connection to peer psm server */
int bt_l2cap_br_chan_connect(struct bt_conn *conn, struct bt_l2cap_chan *chan,
u16_t psm);
/* Send packet data to connected peer */
int bt_l2cap_br_chan_send(struct bt_l2cap_chan *chan, struct net_buf *buf);
/*
* Handle security level changed on link passing HCI status of performed
* security procedure.
*/
void l2cap_br_encrypt_change(struct bt_conn *conn, u8_t hci_status);
/* Handle received data */
void bt_l2cap_br_recv(struct bt_conn *conn, struct net_buf *buf);

View file

@ -0,0 +1,263 @@
/** @file
* @brief Custom logging over UART
*/
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/types.h>
#include <stdbool.h>
#include <zephyr.h>
#include <device.h>
#include <init.h>
#include <drivers/console/uart_pipe.h>
#include <misc/byteorder.h>
#include <misc/printk.h>
#include <uart.h>
#include <bluetooth/buf.h>
#include "monitor.h"
/* This is the same default priority as for other console handlers,
* except that we're not exporting it as a Kconfig variable until a
* clear need arises.
*/
#define MONITOR_INIT_PRIORITY 60
static struct device *monitor_dev;
enum {
BT_LOG_BUSY,
BT_CONSOLE_BUSY,
};
static atomic_t flags;
static struct {
atomic_t cmd;
atomic_t evt;
atomic_t acl_tx;
atomic_t acl_rx;
#if defined(CONFIG_BT_BREDR)
atomic_t sco_tx;
atomic_t sco_rx;
#endif
atomic_t other;
} drops;
extern int _prf(int (*func)(), void *dest,
const char *format, va_list vargs);
static void monitor_send(const void *data, size_t len)
{
const u8_t *buf = data;
while (len--) {
uart_poll_out(monitor_dev, *buf++);
}
}
static void encode_drops(struct bt_monitor_hdr *hdr, u8_t type,
atomic_t *val)
{
atomic_val_t count;
count = atomic_set(val, 0);
if (count) {
hdr->ext[hdr->hdr_len++] = type;
hdr->ext[hdr->hdr_len++] = min(count, 255);
}
}
static inline void encode_hdr(struct bt_monitor_hdr *hdr, u16_t opcode,
u16_t len)
{
struct bt_monitor_ts32 *ts;
hdr->opcode = sys_cpu_to_le16(opcode);
hdr->flags = 0;
ts = (void *)hdr->ext;
ts->type = BT_MONITOR_TS32;
ts->ts32 = sys_cpu_to_le32(k_uptime_get() * 10);
hdr->hdr_len = sizeof(*ts);
encode_drops(hdr, BT_MONITOR_COMMAND_DROPS, &drops.cmd);
encode_drops(hdr, BT_MONITOR_EVENT_DROPS, &drops.evt);
encode_drops(hdr, BT_MONITOR_ACL_TX_DROPS, &drops.acl_tx);
encode_drops(hdr, BT_MONITOR_ACL_RX_DROPS, &drops.acl_rx);
#if defined(CONFIG_BT_BREDR)
encode_drops(hdr, BT_MONITOR_SCO_TX_DROPS, &drops.sco_tx);
encode_drops(hdr, BT_MONITOR_SCO_RX_DROPS, &drops.sco_rx);
#endif
encode_drops(hdr, BT_MONITOR_OTHER_DROPS, &drops.other);
hdr->data_len = sys_cpu_to_le16(4 + hdr->hdr_len + len);
}
static int log_out(int c, void *unused)
{
uart_poll_out(monitor_dev, c);
return 0;
}
static void drop_add(u16_t opcode)
{
switch (opcode) {
case BT_MONITOR_COMMAND_PKT:
atomic_inc(&drops.cmd);
break;
case BT_MONITOR_EVENT_PKT:
atomic_inc(&drops.evt);
break;
case BT_MONITOR_ACL_TX_PKT:
atomic_inc(&drops.acl_tx);
break;
case BT_MONITOR_ACL_RX_PKT:
atomic_inc(&drops.acl_rx);
break;
#if defined(CONFIG_BT_BREDR)
case BT_MONITOR_SCO_TX_PKT:
atomic_inc(&drops.sco_tx);
break;
case BT_MONITOR_SCO_RX_PKT:
atomic_inc(&drops.sco_rx);
break;
#endif
default:
atomic_inc(&drops.other);
break;
}
}
void bt_log(int prio, const char *fmt, ...)
{
struct bt_monitor_user_logging log;
struct bt_monitor_hdr hdr;
const char id[] = "bt";
va_list ap;
int len;
va_start(ap, fmt);
len = vsnprintk(NULL, 0, fmt, ap);
va_end(ap);
if (len < 0) {
return;
}
log.priority = prio;
log.ident_len = sizeof(id);
if (atomic_test_and_set_bit(&flags, BT_LOG_BUSY)) {
drop_add(BT_MONITOR_USER_LOGGING);
return;
}
encode_hdr(&hdr, BT_MONITOR_USER_LOGGING,
sizeof(log) + sizeof(id) + len + 1);
monitor_send(&hdr, BT_MONITOR_BASE_HDR_LEN + hdr.hdr_len);
monitor_send(&log, sizeof(log));
monitor_send(id, sizeof(id));
va_start(ap, fmt);
_vprintk(log_out, NULL, fmt, ap);
va_end(ap);
/* Terminate the string with null */
uart_poll_out(monitor_dev, '\0');
atomic_clear_bit(&flags, BT_LOG_BUSY);
}
void bt_monitor_send(u16_t opcode, const void *data, size_t len)
{
struct bt_monitor_hdr hdr;
if (atomic_test_and_set_bit(&flags, BT_LOG_BUSY)) {
drop_add(opcode);
return;
}
encode_hdr(&hdr, opcode, len);
monitor_send(&hdr, BT_MONITOR_BASE_HDR_LEN + hdr.hdr_len);
monitor_send(data, len);
atomic_clear_bit(&flags, BT_LOG_BUSY);
}
void bt_monitor_new_index(u8_t type, u8_t bus, bt_addr_t *addr,
const char *name)
{
struct bt_monitor_new_index pkt;
pkt.type = type;
pkt.bus = bus;
memcpy(pkt.bdaddr, addr, 6);
strncpy(pkt.name, name, sizeof(pkt.name) - 1);
pkt.name[sizeof(pkt.name) - 1] = '\0';
bt_monitor_send(BT_MONITOR_NEW_INDEX, &pkt, sizeof(pkt));
}
#if !defined(CONFIG_UART_CONSOLE)
static int monitor_console_out(int c)
{
static char buf[128];
static size_t len;
if (atomic_test_and_set_bit(&flags, BT_CONSOLE_BUSY)) {
return c;
}
if (c != '\n' && len < sizeof(buf) - 1) {
buf[len++] = c;
atomic_clear_bit(&flags, BT_CONSOLE_BUSY);
return c;
}
buf[len++] = '\0';
bt_monitor_send(BT_MONITOR_SYSTEM_NOTE, buf, len);
len = 0;
atomic_clear_bit(&flags, BT_CONSOLE_BUSY);
return c;
}
extern void __printk_hook_install(int (*fn)(int));
extern void __stdout_hook_install(int (*fn)(int));
#endif /* !CONFIG_UART_CONSOLE */
#if defined(CONFIG_HAS_DTS) && !defined(CONFIG_BT_MONITOR_ON_DEV_NAME)
#define CONFIG_BT_MONITOR_ON_DEV_NAME CONFIG_UART_CONSOLE_ON_DEV_NAME
#endif
static int bt_monitor_init(struct device *d)
{
ARG_UNUSED(d);
monitor_dev = device_get_binding(CONFIG_BT_MONITOR_ON_DEV_NAME);
#if defined(CONFIG_UART_INTERRUPT_DRIVEN)
uart_irq_rx_disable(monitor_dev);
uart_irq_tx_disable(monitor_dev);
#endif
#if !defined(CONFIG_UART_CONSOLE)
__printk_hook_install(monitor_console_out);
__stdout_hook_install(monitor_console_out);
#endif
return 0;
}
SYS_INIT(bt_monitor_init, PRE_KERNEL_1, MONITOR_INIT_PRIORITY);

View file

@ -0,0 +1,102 @@
/** @file
* @brief Custom monitor protocol logging over UART
*/
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#if defined(CONFIG_BT_DEBUG_MONITOR)
#define BT_MONITOR_NEW_INDEX 0
#define BT_MONITOR_DEL_INDEX 1
#define BT_MONITOR_COMMAND_PKT 2
#define BT_MONITOR_EVENT_PKT 3
#define BT_MONITOR_ACL_TX_PKT 4
#define BT_MONITOR_ACL_RX_PKT 5
#define BT_MONITOR_SCO_TX_PKT 6
#define BT_MONITOR_SCO_RX_PKT 7
#define BT_MONITOR_OPEN_INDEX 8
#define BT_MONITOR_CLOSE_INDEX 9
#define BT_MONITOR_INDEX_INFO 10
#define BT_MONITOR_VENDOR_DIAG 11
#define BT_MONITOR_SYSTEM_NOTE 12
#define BT_MONITOR_USER_LOGGING 13
#define BT_MONITOR_NOP 255
#define BT_MONITOR_TYPE_PRIMARY 0
#define BT_MONITOR_TYPE_AMP 1
/* Extended header types */
#define BT_MONITOR_COMMAND_DROPS 1
#define BT_MONITOR_EVENT_DROPS 2
#define BT_MONITOR_ACL_RX_DROPS 3
#define BT_MONITOR_ACL_TX_DROPS 4
#define BT_MONITOR_SCO_RX_DROPS 5
#define BT_MONITOR_SCO_TX_DROPS 6
#define BT_MONITOR_OTHER_DROPS 7
#define BT_MONITOR_TS32 8
#define BT_MONITOR_BASE_HDR_LEN 6
#if defined(CONFIG_BT_BREDR)
#define BT_MONITOR_EXT_HDR_MAX 19
#else
#define BT_MONITOR_EXT_HDR_MAX 15
#endif
struct bt_monitor_hdr {
u16_t data_len;
u16_t opcode;
u8_t flags;
u8_t hdr_len;
u8_t ext[BT_MONITOR_EXT_HDR_MAX];
} __packed;
struct bt_monitor_ts32 {
u8_t type;
u32_t ts32;
} __packed;
struct bt_monitor_new_index {
u8_t type;
u8_t bus;
u8_t bdaddr[6];
char name[8];
} __packed;
struct bt_monitor_user_logging {
u8_t priority;
u8_t ident_len;
} __packed;
static inline u8_t bt_monitor_opcode(struct net_buf *buf)
{
switch (bt_buf_get_type(buf)) {
case BT_BUF_CMD:
return BT_MONITOR_COMMAND_PKT;
case BT_BUF_EVT:
return BT_MONITOR_EVENT_PKT;
case BT_BUF_ACL_OUT:
return BT_MONITOR_ACL_TX_PKT;
case BT_BUF_ACL_IN:
return BT_MONITOR_ACL_RX_PKT;
default:
return BT_MONITOR_NOP;
}
}
void bt_monitor_send(u16_t opcode, const void *data, size_t len);
void bt_monitor_new_index(u8_t type, u8_t bus, bt_addr_t *addr,
const char *name);
#else /* !CONFIG_BT_DEBUG_MONITOR */
#define bt_monitor_send(opcode, data, len)
#define bt_monitor_new_index(type, bus, addr, name)
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,155 @@
/**
* @file smp.h
* Security Manager Protocol implementation header
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
struct bt_smp_hdr {
u8_t code;
} __packed;
#define BT_SMP_ERR_PASSKEY_ENTRY_FAILED 0x01
#define BT_SMP_ERR_OOB_NOT_AVAIL 0x02
#define BT_SMP_ERR_AUTH_REQUIREMENTS 0x03
#define BT_SMP_ERR_CONFIRM_FAILED 0x04
#define BT_SMP_ERR_PAIRING_NOTSUPP 0x05
#define BT_SMP_ERR_ENC_KEY_SIZE 0x06
#define BT_SMP_ERR_CMD_NOTSUPP 0x07
#define BT_SMP_ERR_UNSPECIFIED 0x08
#define BT_SMP_ERR_REPEATED_ATTEMPTS 0x09
#define BT_SMP_ERR_INVALID_PARAMS 0x0a
#define BT_SMP_ERR_DHKEY_CHECK_FAILED 0x0b
#define BT_SMP_ERR_NUMERIC_COMP_FAILED 0x0c
#define BT_SMP_ERR_BREDR_PAIRING_IN_PROGRESS 0x0d
#define BT_SMP_ERR_CROSS_TRANSP_NOT_ALLOWED 0x0e
#define BT_SMP_IO_DISPLAY_ONLY 0x00
#define BT_SMP_IO_DISPLAY_YESNO 0x01
#define BT_SMP_IO_KEYBOARD_ONLY 0x02
#define BT_SMP_IO_NO_INPUT_OUTPUT 0x03
#define BT_SMP_IO_KEYBOARD_DISPLAY 0x04
#define BT_SMP_OOB_NOT_PRESENT 0x00
#define BT_SMP_OOB_PRESENT 0x01
#define BT_SMP_MIN_ENC_KEY_SIZE 7
#define BT_SMP_MAX_ENC_KEY_SIZE 16
#define BT_SMP_DIST_ENC_KEY 0x01
#define BT_SMP_DIST_ID_KEY 0x02
#define BT_SMP_DIST_SIGN 0x04
#define BT_SMP_DIST_LINK_KEY 0x08
#define BT_SMP_DIST_MASK 0x0f
#define BT_SMP_AUTH_NONE 0x00
#define BT_SMP_AUTH_BONDING 0x01
#define BT_SMP_AUTH_MITM 0x04
#define BT_SMP_AUTH_SC 0x08
#define BT_SMP_AUTH_KEYPRESS 0x10
#define BT_SMP_AUTH_CT2 0x20
#define BT_SMP_CMD_PAIRING_REQ 0x01
#define BT_SMP_CMD_PAIRING_RSP 0x02
struct bt_smp_pairing {
u8_t io_capability;
u8_t oob_flag;
u8_t auth_req;
u8_t max_key_size;
u8_t init_key_dist;
u8_t resp_key_dist;
} __packed;
#define BT_SMP_CMD_PAIRING_CONFIRM 0x03
struct bt_smp_pairing_confirm {
u8_t val[16];
} __packed;
#define BT_SMP_CMD_PAIRING_RANDOM 0x04
struct bt_smp_pairing_random {
u8_t val[16];
} __packed;
#define BT_SMP_CMD_PAIRING_FAIL 0x05
struct bt_smp_pairing_fail {
u8_t reason;
} __packed;
#define BT_SMP_CMD_ENCRYPT_INFO 0x06
struct bt_smp_encrypt_info {
u8_t ltk[16];
} __packed;
#define BT_SMP_CMD_MASTER_IDENT 0x07
struct bt_smp_master_ident {
u16_t ediv;
u64_t rand;
} __packed;
#define BT_SMP_CMD_IDENT_INFO 0x08
struct bt_smp_ident_info {
u8_t irk[16];
} __packed;
#define BT_SMP_CMD_IDENT_ADDR_INFO 0x09
struct bt_smp_ident_addr_info {
bt_addr_le_t addr;
} __packed;
#define BT_SMP_CMD_SIGNING_INFO 0x0a
struct bt_smp_signing_info {
u8_t csrk[16];
} __packed;
#define BT_SMP_CMD_SECURITY_REQUEST 0x0b
struct bt_smp_security_request {
u8_t auth_req;
} __packed;
#define BT_SMP_CMD_PUBLIC_KEY 0x0c
struct bt_smp_public_key {
u8_t x[32];
u8_t y[32];
} __packed;
#define BT_SMP_DHKEY_CHECK 0x0d
struct bt_smp_dhkey_check {
u8_t e[16];
} __packed;
int bt_smp_send_pairing_req(struct bt_conn *conn);
int bt_smp_send_security_req(struct bt_conn *conn);
void bt_smp_update_keys(struct bt_conn *conn);
bool bt_smp_get_tk(struct bt_conn *conn, u8_t *tk);
int bt_smp_br_send_pairing_req(struct bt_conn *conn);
int bt_smp_init(void);
int bt_smp_auth_passkey_entry(struct bt_conn *conn, unsigned int passkey);
int bt_smp_auth_passkey_confirm(struct bt_conn *conn);
int bt_smp_auth_pairing_confirm(struct bt_conn *conn);
int bt_smp_auth_cancel(struct bt_conn *conn);
/** brief Verify signed message
*
* @param conn Bluetooth connection
* @param buf received packet buffer with message and signature
*
* @return 0 in success, error code otherwise
*/
int bt_smp_sign_verify(struct bt_conn *conn, struct net_buf *buf);
/** brief Sign message
*
* @param conn Bluetooth connection
* @param buf message buffer
*
* @return 0 in success, error code otherwise
*/
int bt_smp_sign(struct bt_conn *conn, struct net_buf *buf);

View file

@ -0,0 +1,103 @@
/**
* @file smp_null.c
* Security Manager Protocol stub
*/
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr.h>
#include <errno.h>
#include <atomic.h>
#include <misc/util.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>
#include <bluetooth/buf.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
#include "common/log.h"
#include "hci_core.h"
#include "conn_internal.h"
#include "l2cap_internal.h"
#include "smp.h"
static struct bt_l2cap_le_chan bt_smp_pool[CONFIG_BT_MAX_CONN];
int bt_smp_sign_verify(struct bt_conn *conn, struct net_buf *buf)
{
return -ENOTSUP;
}
int bt_smp_sign(struct bt_conn *conn, struct net_buf *buf)
{
return -ENOTSUP;
}
static void bt_smp_recv(struct bt_l2cap_chan *chan, struct net_buf *buf)
{
struct bt_conn *conn = chan->conn;
struct bt_smp_pairing_fail *rsp;
struct bt_smp_hdr *hdr;
/* If a device does not support pairing then it shall respond with
* a Pairing Failed command with the reason set to "Pairing Not
* Supported" when any command is received.
* Core Specification Vol. 3, Part H, 3.3
*/
buf = bt_l2cap_create_pdu(NULL, 0);
/* NULL is not a possible return due to K_FOREVER */
hdr = net_buf_add(buf, sizeof(*hdr));
hdr->code = BT_SMP_CMD_PAIRING_FAIL;
rsp = net_buf_add(buf, sizeof(*rsp));
rsp->reason = BT_SMP_ERR_PAIRING_NOTSUPP;
bt_l2cap_send(conn, BT_L2CAP_CID_SMP, buf);
}
static int bt_smp_accept(struct bt_conn *conn, struct bt_l2cap_chan **chan)
{
int i;
static struct bt_l2cap_chan_ops ops = {
.recv = bt_smp_recv,
};
BT_DBG("conn %p handle %u", conn, conn->handle);
for (i = 0; i < ARRAY_SIZE(bt_smp_pool); i++) {
struct bt_l2cap_le_chan *smp = &bt_smp_pool[i];
if (smp->chan.conn) {
continue;
}
smp->chan.ops = &ops;
*chan = &smp->chan;
return 0;
}
BT_ERR("No available SMP context for conn %p", conn);
return -ENOMEM;
}
int bt_smp_init(void)
{
static struct bt_l2cap_fixed_chan chan = {
.cid = BT_L2CAP_CID_SMP,
.accept = bt_smp_accept,
};
bt_l2cap_le_fixed_chan_register(&chan);
return 0;
}

View file

@ -0,0 +1,229 @@
/*
* Copyright (c) 2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <string.h>
#include <misc/printk.h>
#include <zephyr.h>
#include <init.h>
#include <fs.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/storage.h>
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_CORE)
#include "common/log.h"
#define STORAGE_ROOT "/bt"
/* Required file name length for full storage support. If the maximum
* file name length supported by the chosen file system is less than
* this value, then only local keys are supported (/bt/abcd).
*/
#define STORAGE_FILE_NAME_LEN 13
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
/* /bt/aabbccddeeff0/abcd */
#define STORAGE_PATH_MAX 23
#else
/* /bt/abcd */
#define STORAGE_PATH_MAX 9
#endif
enum storage_access {
STORAGE_READ,
STORAGE_WRITE
};
static int storage_open(const bt_addr_le_t *addr, u16_t key,
enum storage_access access, fs_file_t *file)
{
char path[STORAGE_PATH_MAX];
if (addr) {
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
int len;
len = snprintk(path, sizeof(path),
STORAGE_ROOT "/%02X%02X%02X%02X%02X%02X%u",
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type);
/* Create the subdirectory if necessary */
if (access == STORAGE_WRITE) {
struct fs_dirent entry;
int err;
err = fs_stat(path, &entry);
if (err) {
err = fs_mkdir(path);
if (err) {
return err;
}
}
}
snprintk(path + len, sizeof(path) - len, "/%04x", key);
#else
return -ENAMETOOLONG;
#endif
} else {
snprintk(path, sizeof(path), STORAGE_ROOT "/%04x", key);
}
return fs_open(file, path);
}
static ssize_t storage_read(const bt_addr_le_t *addr, u16_t key, void *data,
size_t length)
{
fs_file_t file;
ssize_t ret;
ret = storage_open(addr, key, STORAGE_READ, &file);
if (ret) {
return ret;
}
ret = fs_read(&file, data, length);
fs_close(&file);
return ret;
}
static ssize_t storage_write(const bt_addr_le_t *addr, u16_t key,
const void *data, size_t length)
{
fs_file_t file;
ssize_t ret;
ret = storage_open(addr, key, STORAGE_WRITE, &file);
if (ret) {
return ret;
}
ret = fs_write(&file, data, length);
fs_close(&file);
return ret;
}
static int unlink_recursive(char path[STORAGE_PATH_MAX])
{
size_t path_len;
fs_dir_t dir;
int err;
err = fs_opendir(&dir, path);
if (err) {
return err;
}
/* We calculate this up-front so we can keep reusing the same
* buffer for the path when recursing.
*/
path_len = strlen(path);
while (1) {
struct fs_dirent entry;
err = fs_readdir(&dir, &entry);
if (err) {
break;
}
if (entry.name[0] == '\0') {
break;
}
snprintk(path + path_len, STORAGE_PATH_MAX - path_len, "/%s",
entry.name);
if (entry.type == FS_DIR_ENTRY_DIR) {
err = unlink_recursive(path);
} else {
err = fs_unlink(path);
}
if (err) {
break;
}
}
fs_closedir(&dir);
/* Return to the original value */
path[path_len] = '\0';
fs_unlink(path);
return err;
}
static int storage_clear(const bt_addr_le_t *addr)
{
char path[STORAGE_PATH_MAX];
int err;
if (addr) {
#if MAX_FILE_NAME >= STORAGE_FILE_NAME_LEN
snprintk(path, STORAGE_PATH_MAX,
STORAGE_ROOT "/%02X%02X%02X%02X%02X%02X%u",
addr->a.val[5], addr->a.val[4], addr->a.val[3],
addr->a.val[2], addr->a.val[1], addr->a.val[0],
addr->type);
return unlink_recursive(path);
#else
return -ENAMETOOLONG;
#endif
}
/* unlink_recursive() uses the given path as a buffer for
* constructing sub-paths, so we can't give it a string literal
* such as STORAGE_ROOT directly.
*/
strcpy(path, STORAGE_ROOT);
err = unlink_recursive(path);
if (err) {
return err;
}
return fs_mkdir(STORAGE_ROOT);
}
static int storage_init(struct device *unused)
{
static const struct bt_storage storage = {
.read = storage_read,
.write = storage_write,
.clear = storage_clear
};
struct fs_dirent entry;
int err;
err = fs_stat(STORAGE_ROOT, &entry);
if (err) {
BT_WARN("%s doesn't seem to exist (err %d). Creating it.",
STORAGE_ROOT, err);
err = fs_mkdir(STORAGE_ROOT);
if (err) {
BT_ERR("Unable to create %s (err %d)",
STORAGE_ROOT, err);
return err;
}
}
bt_storage_register(&storage);
return 0;
}
SYS_INIT(storage_init, APPLICATION, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);

View file

@ -0,0 +1,120 @@
/* uuid.c - Bluetooth UUID handling */
/*
* Copyright (c) 2015-2016 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include <misc/byteorder.h>
#include <misc/printk.h>
#include <bluetooth/uuid.h>
#define UUID_16_BASE_OFFSET 12
/* TODO: Decide whether to continue using BLE format or switch to RFC 4122 */
/* Base UUID : 0000[0000]-0000-1000-8000-00805F9B34FB ->
* { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
* 0x00, 0x10, 0x00, 0x00, [0x00, 0x00], 0x00, 0x00 }
* 0x2800 : 0000[2800]-0000-1000-8000-00805F9B34FB ->
* { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
* 0x00, 0x10, 0x00, 0x00, [0x00, 0x28], 0x00, 0x00 }
* little endian 0x2800 : [00 28] -> no swapping required
* big endian 0x2800 : [28 00] -> swapping required
*/
static const struct bt_uuid_128 uuid128_base = {
.uuid.type = BT_UUID_TYPE_128,
.val = { 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
};
static void uuid_to_uuid128(const struct bt_uuid *src, struct bt_uuid_128 *dst)
{
switch (src->type) {
case BT_UUID_TYPE_16:
*dst = uuid128_base;
sys_put_le16(BT_UUID_16(src)->val,
&dst->val[UUID_16_BASE_OFFSET]);
return;
case BT_UUID_TYPE_32:
*dst = uuid128_base;
sys_put_le32(BT_UUID_32(src)->val,
&dst->val[UUID_16_BASE_OFFSET]);
return;
case BT_UUID_TYPE_128:
memcpy(dst, src, sizeof(*dst));
return;
}
}
static int uuid128_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2)
{
struct bt_uuid_128 uuid1, uuid2;
uuid_to_uuid128(u1, &uuid1);
uuid_to_uuid128(u2, &uuid2);
return memcmp(uuid1.val, uuid2.val, 16);
}
int bt_uuid_cmp(const struct bt_uuid *u1, const struct bt_uuid *u2)
{
/* Convert to 128 bit if types don't match */
if (u1->type != u2->type)
return uuid128_cmp(u1, u2);
switch (u1->type) {
case BT_UUID_TYPE_16:
return (int)BT_UUID_16(u1)->val - (int)BT_UUID_16(u2)->val;
case BT_UUID_TYPE_32:
return (int)BT_UUID_32(u1)->val - (int)BT_UUID_32(u2)->val;
case BT_UUID_TYPE_128:
return memcmp(BT_UUID_128(u1)->val, BT_UUID_128(u2)->val, 16);
}
return -EINVAL;
}
#if defined(CONFIG_BT_DEBUG)
void bt_uuid_to_str(const struct bt_uuid *uuid, char *str, size_t len)
{
u32_t tmp1, tmp5;
u16_t tmp0, tmp2, tmp3, tmp4;
switch (uuid->type) {
case BT_UUID_TYPE_16:
snprintk(str, len, "%04x", BT_UUID_16(uuid)->val);
break;
case BT_UUID_TYPE_32:
snprintk(str, len, "%04x", BT_UUID_32(uuid)->val);
break;
case BT_UUID_TYPE_128:
memcpy(&tmp0, &BT_UUID_128(uuid)->val[0], sizeof(tmp0));
memcpy(&tmp1, &BT_UUID_128(uuid)->val[2], sizeof(tmp1));
memcpy(&tmp2, &BT_UUID_128(uuid)->val[6], sizeof(tmp2));
memcpy(&tmp3, &BT_UUID_128(uuid)->val[8], sizeof(tmp3));
memcpy(&tmp4, &BT_UUID_128(uuid)->val[10], sizeof(tmp4));
memcpy(&tmp5, &BT_UUID_128(uuid)->val[12], sizeof(tmp5));
snprintk(str, len, "%08x-%04x-%04x-%04x-%08x%04x",
tmp5, tmp4, tmp3, tmp2, tmp1, tmp0);
break;
default:
memset(str, 0, len);
return;
}
}
const char *bt_uuid_str(const struct bt_uuid *uuid)
{
static char str[37];
bt_uuid_to_str(uuid, str, sizeof(str));
return str;
}
#endif /* CONFIG_BT_DEBUG */