Merge pull request #511 from rymanluk/porting

nimble: Port Bluetooth Mesh from Zephyr to Mynewt

X-Original-Commit: afe2a6a94aa65323684a54f1eff85ee63d8ddde3
This commit is contained in:
Łukasz Rymanowski
2017-09-01 15:10:20 +02:00
committed by GitHub
36 changed files with 15450 additions and 19 deletions
+7
View File
@@ -23,6 +23,8 @@
#include <inttypes.h>
#include "host/ble_hs.h"
#include "host/ble_hs_adv.h"
#include "syscfg/syscfg.h"
#ifdef __cplusplus
extern "C" {
#endif
@@ -698,6 +700,11 @@ int ble_gap_set_prefered_default_le_phy(uint8_t tx_phys_mask,
#define BLE_GAP_LE_PHY_CODED_S8 2
int ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask,
uint8_t rx_phys_mask, uint16_t phy_opts);
#if MYNEWT_VAL(BLE_MESH)
int ble_gap_mesh_cb_register(ble_gap_event_fn *cb, void *cb_arg);
#endif
#ifdef __cplusplus
}
#endif
+3
View File
@@ -126,6 +126,9 @@ struct ble_hs_adv_fields {
#define BLE_HS_ADV_TYPE_SVC_DATA_UUID32 0x20
#define BLE_HS_ADV_TYPE_SVC_DATA_UUID128 0x21
#define BLE_HS_ADV_TYPE_URI 0x24
#define BLE_HS_ADV_TYPE_MESH_PROV 0x29
#define BLE_HS_ADV_TYPE_MESH_MESSAGE 0x2a
#define BLE_HS_ADV_TYPE_MESH_BEACON 0x2b
#define BLE_HS_ADV_TYPE_MFG_DATA 0xff
#define BLE_HS_ADV_FLAGS_LEN 1
+386
View File
@@ -0,0 +1,386 @@
/* atomic operations */
/*
* Copyright (c) 1997-2015, Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ATOMIC_H__
#define __ATOMIC_H__
#ifdef __cplusplus
extern "C"
{
#endif
typedef int atomic_t;
typedef atomic_t atomic_val_t;
/**
* @defgroup atomic_apis Atomic Services APIs
* @ingroup kernel_apis
* @{
*/
/**
* @brief Atomic compare-and-set.
*
* This routine performs an atomic compare-and-set on @a target. If the current
* value of @a target equals @a old_value, @a target is set to @a new_value.
* If the current value of @a target does not equal @a old_value, @a target
* is left unchanged.
*
* @param target Address of atomic variable.
* @param old_value Original value to compare against.
* @param new_value New value to store.
* @return 1 if @a new_value is written, 0 otherwise.
*/
static inline int atomic_cas(atomic_t *target, atomic_val_t old_value,
atomic_val_t new_value)
{
return __atomic_compare_exchange_n(target, &old_value, new_value,
0, __ATOMIC_SEQ_CST,
__ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic addition.
*
* This routine performs an atomic addition on @a target.
*
* @param target Address of atomic variable.
* @param value Value to add.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_add(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_add(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic subtraction.
*
* This routine performs an atomic subtraction on @a target.
*
* @param target Address of atomic variable.
* @param value Value to subtract.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_sub(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_sub(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic increment.
*
* This routine performs an atomic increment by 1 on @a target.
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_inc(atomic_t *target)
{
return atomic_add(target, 1);
}
/**
*
* @brief Atomic decrement.
*
* This routine performs an atomic decrement by 1 on @a target.
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_dec(atomic_t *target)
{
return atomic_sub(target, 1);
}
/**
*
* @brief Atomic get.
*
* This routine performs an atomic read on @a target.
*
* @param target Address of atomic variable.
*
* @return Value of @a target.
*/
static inline atomic_val_t atomic_get(const atomic_t *target)
{
return __atomic_load_n(target, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic get-and-set.
*
* This routine atomically sets @a target to @a value and returns
* the previous value of @a target.
*
* @param target Address of atomic variable.
* @param value Value to write to @a target.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_set(atomic_t *target, atomic_val_t value)
{
/* This builtin, as described by Intel, is not a traditional
* test-and-set operation, but rather an atomic exchange operation. It
* writes value into *ptr, and returns the previous contents of *ptr.
*/
return __atomic_exchange_n(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic clear.
*
* This routine atomically sets @a target to zero and returns its previous
* value. (Hence, it is equivalent to atomic_set(target, 0).)
*
* @param target Address of atomic variable.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_clear(atomic_t *target)
{
return atomic_set(target, 0);
}
/**
*
* @brief Atomic bitwise inclusive OR.
*
* This routine atomically sets @a target to the bitwise inclusive OR of
* @a target and @a value.
*
* @param target Address of atomic variable.
* @param value Value to OR.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_or(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_or(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise exclusive OR (XOR).
*
* This routine atomically sets @a target to the bitwise exclusive OR (XOR) of
* @a target and @a value.
*
* @param target Address of atomic variable.
* @param value Value to XOR
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_xor(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_xor(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise AND.
*
* This routine atomically sets @a target to the bitwise AND of @a target
* and @a value.
*
* @param target Address of atomic variable.
* @param value Value to AND.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_and(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_and(target, value, __ATOMIC_SEQ_CST);
}
/**
*
* @brief Atomic bitwise NAND.
*
* This routine atomically sets @a target to the bitwise NAND of @a target
* and @a value. (This operation is equivalent to target = ~(target & value).)
*
* @param target Address of atomic variable.
* @param value Value to NAND.
*
* @return Previous value of @a target.
*/
static inline atomic_val_t atomic_nand(atomic_t *target, atomic_val_t value)
{
return __atomic_fetch_nand(target, value, __ATOMIC_SEQ_CST);
}
/**
* @brief Initialize an atomic variable.
*
* This macro can be used to initialize an atomic variable. For example,
* @code atomic_t my_var = ATOMIC_INIT(75); @endcode
*
* @param i Value to assign to atomic variable.
*/
#define ATOMIC_INIT(i) (i)
/**
* @cond INTERNAL_HIDDEN
*/
#define ATOMIC_BITS (sizeof(atomic_val_t) * 8)
#define ATOMIC_MASK(bit) (1 << ((bit) & (ATOMIC_BITS - 1)))
#define ATOMIC_ELEM(addr, bit) ((addr) + ((bit) / ATOMIC_BITS))
/**
* INTERNAL_HIDDEN @endcond
*/
/**
* @brief Define an array of atomic variables.
*
* This macro defines an array of atomic variables containing at least
* @a num_bits bits.
*
* @note
* If used from file scope, the bits of the array are initialized to zero;
* if used from within a function, the bits are left uninitialized.
*
* @param name Name of array of atomic variables.
* @param num_bits Number of bits needed.
*/
#define ATOMIC_DEFINE(name, num_bits) \
atomic_t name[1 + ((num_bits) - 1) / ATOMIC_BITS]
/**
* @brief Atomically test a bit.
*
* This routine tests whether bit number @a bit of @a target is set or not.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_bit(const atomic_t *target, int bit)
{
atomic_val_t val = atomic_get(ATOMIC_ELEM(target, bit));
return (1 & (val >> (bit & (ATOMIC_BITS - 1))));
}
/**
* @brief Atomically test and clear a bit.
*
* Atomically clear bit number @a bit of @a target and return its old value.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_and_clear_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_val_t old;
old = atomic_and(ATOMIC_ELEM(target, bit), ~mask);
return (old & mask) != 0;
}
/**
* @brief Atomically set a bit.
*
* Atomically set bit number @a bit of @a target and return its old value.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return 1 if the bit was set, 0 if it wasn't.
*/
static inline int
atomic_test_and_set_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_val_t old;
old = atomic_or(ATOMIC_ELEM(target, bit), mask);
return (old & mask) != 0;
}
/**
* @brief Atomically clear a bit.
*
* Atomically clear bit number @a bit of @a target.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return N/A
*/
static inline void
atomic_clear_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_and(ATOMIC_ELEM(target, bit), ~mask);
}
/**
* @brief Atomically set a bit.
*
* Atomically set bit number @a bit of @a target.
* The target may be a single atomic variable or an array of them.
*
* @param target Address of atomic variable or array.
* @param bit Bit number (starting from 0).
*
* @return N/A
*/
static inline void
atomic_set_bit(atomic_t *target, int bit)
{
atomic_val_t mask = ATOMIC_MASK(bit);
atomic_or(ATOMIC_ELEM(target, bit), mask);
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __ATOMIC_H__ */
+318
View File
@@ -0,0 +1,318 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef _MESH_GLUE_
#define _MESH_GLUE_
#include <assert.h>
#include "syscfg/syscfg.h"
#include "os/os_mbuf.h"
#include "os/os_mbuf.h"
#include "os/os_callout.h"
#include "os/os_eventq.h"
#include "atomic.h"
#include "nimble/ble.h"
#include "host/ble_hs.h"
#include "host/ble_uuid.h"
#include "../src/ble_sm_priv.h"
#include "../src/ble_hs_hci_priv.h"
#include "tinycrypt/aes.h"
#include "tinycrypt/constants.h"
#include "tinycrypt/utils.h"
#include "tinycrypt/cmac_mode.h"
#include "tinycrypt/ecc_dh.h"
#define u8_t uint8_t
#define s8_t int8_t
#define u16_t uint16_t
#define u32_t uint32_t
#define u64_t uint64_t
#define s64_t int64_t
#define s32_t int32_t
typedef size_t ssize_t;
/** @brief Helper to declare elements of bt_data arrays
*
* This macro is mainly for creating an array of struct bt_data
* elements which is then passed to bt_le_adv_start().
*
* @param _type Type of advertising data field
* @param _data Pointer to the data field payload
* @param _data_len Number of bytes behind the _data pointer
*/
#define BT_DATA(_type, _data, _data_len) \
{ \
.type = (_type), \
.data_len = (_data_len), \
.data = (const u8_t *)(_data), \
}
/** @brief Helper to declare elements of bt_data arrays
*
* This macro is mainly for creating an array of struct bt_data
* elements which is then passed to bt_le_adv_start().
*
* @param _type Type of advertising data field
* @param _bytes Variable number of single-byte parameters
*/
#define BT_DATA_BYTES(_type, _bytes...) \
BT_DATA(_type, ((u8_t []) { _bytes }), \
sizeof((u8_t []) { _bytes }))
/* EIR/AD data type definitions */
#define BT_DATA_FLAGS 0x01 /* AD flags */
#define BT_DATA_UUID16_SOME 0x02 /* 16-bit UUID, more available */
#define BT_DATA_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
#define BT_DATA_UUID32_SOME 0x04 /* 32-bit UUID, more available */
#define BT_DATA_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
#define BT_DATA_UUID128_SOME 0x06 /* 128-bit UUID, more available */
#define BT_DATA_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
#define BT_DATA_NAME_SHORTENED 0x08 /* Shortened name */
#define BT_DATA_NAME_COMPLETE 0x09 /* Complete name */
#define BT_DATA_TX_POWER 0x0a /* Tx Power */
#define BT_DATA_SOLICIT16 0x14 /* Solicit UUIDs, 16-bit */
#define BT_DATA_SOLICIT128 0x15 /* Solicit UUIDs, 128-bit */
#define BT_DATA_SVC_DATA16 0x16 /* Service data, 16-bit UUID */
#define BT_DATA_GAP_APPEARANCE 0x19 /* GAP appearance */
#define BT_DATA_SOLICIT32 0x1f /* Solicit UUIDs, 32-bit */
#define BT_DATA_SVC_DATA32 0x20 /* Service data, 32-bit UUID */
#define BT_DATA_SVC_DATA128 0x21 /* Service data, 128-bit UUID */
#define BT_DATA_MESH_PROV 0x29 /* Mesh Provisioning PDU */
#define BT_DATA_MESH_MESSAGE 0x2a /* Mesh Networking PDU */
#define BT_DATA_MESH_BEACON 0x2b /* Mesh Beacon */
#define BT_DATA_MANUFACTURER_DATA 0xff /* Manufacturer Specific Data */
#define BT_LE_AD_LIMITED 0x01 /* Limited Discoverable */
#define BT_LE_AD_GENERAL 0x02 /* General Discoverable */
#define BT_LE_AD_NO_BREDR 0x04 /* BR/EDR not supported */
#define sys_put_be16(a,b) put_be16(b, a)
#define sys_put_le16(a,b) put_le16(b, a)
#define sys_put_be32(a,b) put_be32(b, a)
#define sys_get_be16(a) get_be16(a)
#define sys_get_le16(a) get_le16(a)
#define sys_get_be32(a) get_be32(a)
#define sys_cpu_to_be16(a) htobe16(a)
#define sys_cpu_to_be32(a) htobe32(a)
#define sys_be32_to_cpu(a) be32toh(a)
#define sys_be16_to_cpu(a) be16toh(a)
#define sys_le16_to_cpu(a) le16toh(a)
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define CODE_UNREACHABLE __builtin_unreachable()
#define __ASSERT(code, str) \
do { \
if (!(code)) BT_ERR(str); \
assert(code); \
} while (0);
#define __packed __attribute__((__packed__))
#define MSEC_PER_SEC (1000)
#define K_MSEC(ms) (ms)
#define K_SECONDS(s) K_MSEC((s) * MSEC_PER_SEC)
#define K_MINUTES(m) K_SECONDS((m) * 60)
#define K_HOURS(h) K_MINUTES((h) * 60)
#define BT_GAP_ADV_FAST_INT_MIN_1 0x0030 /* 30 ms */
#define BT_GAP_ADV_FAST_INT_MAX_1 0x0060 /* 60 ms */
#define BT_GAP_ADV_FAST_INT_MIN_2 0x00a0 /* 100 ms */
#define BT_GAP_ADV_FAST_INT_MAX_2 0x00f0 /* 150 ms */
#define BT_GAP_ADV_SLOW_INT_MIN 0x0640 /* 1 s */
#define BT_GAP_ADV_SLOW_INT_MAX 0x0780 /* 1.2 s */
#define BT_WARN(fmt, ...) BLE_HS_LOG(WARN, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_DBG(fmt, ...) BLE_HS_LOG(DEBUG, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_INFO(fmt, ...) BLE_HS_LOG(INFO, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_ERR(fmt, ...) BLE_HS_LOG(ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_GATT_ERR(_att_err) (-(_att_err))
typedef ble_addr_t bt_addr_le_t;
#define k_fifo_init(queue) os_eventq_init(queue)
#define net_buf_simple_tailroom(buf) OS_MBUF_TRAILINGSPACE(buf)
#define net_buf_tailroom(buf) net_buf_simple_tailroom(buf)
#define net_buf_headroom(buf) ((buf)->om_data - &(buf)->om_databuf[buf->om_pkthdr_len])
#define net_buf_simple_headroom(buf) net_buf_headroom(buf)
#define net_buf_simple_tail(buf) ((buf)->om_data + (buf)->om_len)
struct net_buf_simple_state {
/** Offset of the data pointer from the beginning of the storage */
u16_t offset;
/** Length of data */
u16_t len;
};
static inline struct os_mbuf * NET_BUF_SIMPLE(uint16_t size)
{
struct os_mbuf *buf;
buf = os_msys_get(size, 0);
assert(buf);
return buf;
}
#define K_NO_WAIT (0)
#define K_FOREVER (-1)
/* This is by purpose */
static inline void net_buf_simple_init(struct os_mbuf *buf,
size_t reserve_head)
{
/* This is called in Zephyr after init.
* Note in Mynewt case we don't care abour reserved head*/
buf->om_data = &buf->om_databuf[buf->om_pkthdr_len] + reserve_head;
buf->om_len = 0;
}
void net_buf_put(struct os_eventq *fifo, struct os_mbuf *buf);
void * net_buf_ref(struct os_mbuf *om);
void net_buf_unref(struct os_mbuf *om);
uint16_t net_buf_simple_pull_le16(struct os_mbuf *om);
uint16_t net_buf_simple_pull_be16(struct os_mbuf *om);
uint32_t net_buf_simple_pull_be32(struct os_mbuf *om);
uint8_t net_buf_simple_pull_u8(struct os_mbuf *om);
void net_buf_simple_add_le16(struct os_mbuf *om, uint16_t val);
void net_buf_simple_add_be16(struct os_mbuf *om, uint16_t val);
void net_buf_simple_add_u8(struct os_mbuf *om, uint8_t val);
void net_buf_simple_add_be32(struct os_mbuf *om, uint32_t val);
void net_buf_add_zeros(struct os_mbuf *om, uint8_t len);
void net_buf_simple_push_le16(struct os_mbuf *om, uint16_t val);
void net_buf_simple_push_be16(struct os_mbuf *om, uint16_t val);
void net_buf_simple_push_u8(struct os_mbuf *om, uint8_t val);
void *net_buf_simple_pull(struct os_mbuf *om, uint8_t len);
void *net_buf_simple_add(struct os_mbuf *om, uint8_t len);
bool k_fifo_is_empty(struct os_eventq *q);
void * net_buf_get(struct os_eventq *fifo,s32_t t);
uint8_t *net_buf_simple_push(struct os_mbuf *om, uint8_t len);
void net_buf_reserve(struct os_mbuf *om, size_t reserve);
#define net_buf_add_mem(a,b,c) os_mbuf_append(a,b,c)
#define net_buf_simple_add_mem(a,b,c) os_mbuf_append(a,b,c)
#define net_buf_add_u8(a,b) net_buf_simple_add_u8(a,b)
#define net_buf_add(a,b) net_buf_simple_add(a,b)
#define net_buf_clone(a, b) os_mbuf_dup(a)
#define net_buf_add_be32(a, b) net_buf_simple_add_be32(a, b)
#define net_buf_add_be16(a, b) net_buf_simple_add_be16(a, b)
#define bt_le_adv_stop() ble_gap_adv_stop()
#define BT_GATT_CCC_NOTIFY BLE_GATT_CHR_PROP_NOTIFY
#define bt_gatt_attr ble_gatt_attr
/** Description of different data types that can be encoded into
* advertising data. Used to form arrays that are passed to the
* bt_le_adv_start() function.
*/
struct bt_data {
u8_t type;
u8_t data_len;
const u8_t *data;
};
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;
};
typedef void (*bt_dh_key_cb_t)(const u8_t key[32]);
int bt_dh_key_gen(const u8_t remote_pk[64], bt_dh_key_cb_t cb);
int bt_pub_key_gen(struct bt_pub_key_cb *new_cb);
uint8_t *bt_pub_key_get(void);
int bt_rand(void *buf, size_t len);
const char * bt_hex(const void *buf, size_t len);
int bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data);
void bt_mesh_register_gatt(void);
int bt_le_adv_start(const struct ble_gap_adv_params *param,
const struct bt_data *ad, size_t ad_len,
const struct bt_data *sd, size_t sd_len);
struct k_delayed_work {
struct os_callout work;
};
void k_work_init(struct os_callout *work, os_event_fn handler);
void k_delayed_work_init(struct k_delayed_work *w, os_event_fn *f);
void k_delayed_work_cancel(struct k_delayed_work *w);
void k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms);
int64_t k_uptime_get(void);
u32_t k_uptime_get_32(void);
void k_work_submit(struct os_callout *w);
void k_work_add_arg(struct os_callout *w, void *arg);
void k_delayed_work_add_arg(struct k_delayed_work *w, void *arg);
uint32_t k_delayed_work_remaining_get(struct k_delayed_work *w);
static inline void net_buf_simple_save(struct os_mbuf *buf,
struct net_buf_simple_state *state)
{
state->offset = net_buf_simple_headroom(buf);
state->len = buf->om_len;
}
static inline void net_buf_simple_restore(struct os_mbuf *buf,
struct net_buf_simple_state *state)
{
buf->om_data = &buf->om_databuf[buf->om_pkthdr_len] + state->offset;
buf->om_len = state->len;
}
static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
{
__ASSERT(((src < dst && (src + length) <= dst) ||
(src > dst && (dst + length) <= src)),
"Source and destination buffers must not overlap");
src += length - 1;
for (; length > 0; length--) {
*((u8_t *)dst++) = *((u8_t *)src--);
}
}
#define popcount(x) __builtin_popcount(x)
static inline unsigned int find_lsb_set(u32_t op)
{
return __builtin_ffs(op);
}
static inline unsigned int find_msb_set(u32_t op)
{
if (!op)
return 0;
return 32 - __builtin_clz(op);
}
#endif
+617
View File
@@ -0,0 +1,617 @@
/** @file
* @brief Bluetooth Mesh Profile APIs.
*/
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BT_MESH_H
#define __BT_MESH_H
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include "mesh/glue.h"
/**
* @brief Parsing state of a buffer.
*
* This is used for temporarily storing the parsing state of a buffer
* while giving control of the parsing to a routine which we don't
* control.
*/
#define BIT(x) (1U << (x))
#define BIT_MASK(n) (BIT(n) - 1)
/**
* @brief Bluetooth Mesh Proxy
* @defgroup bt_mesh_proxy Bluetooth Mesh Proxy
* @ingroup bt_mesh
* @{
*/
/**
* @brief Enable advertising with Node Identity.
*
* This API requires that GATT Proxy support has been enabled. Once called
* each subnet will start advertising using Node Identity for the next
* 60 seconds.
*
* @return 0 on success, or (negative) error code on failure.
*/
int
bt_mesh_proxy_identity_enable(void);
/**
* @}
*/
/**
* @brief Bluetooth Mesh Composition
* @defgroup bt_comp Bluetooth Mesh Composition
* @ingroup bt_mesh
* @{
*/
#define BT_MESH_ADDR_UNASSIGNED 0x0000
#define BT_MESH_ADDR_ALL_NODES 0xffff
#define BT_MESH_ADDR_PROXIES 0xfffc
#define BT_MESH_ADDR_FRIENDS 0xfffd
#define BT_MESH_ADDR_RELAYS 0xfffe
#define BT_MESH_KEY_UNUSED 0xffff
#define BT_MESH_KEY_DEV 0xfffe
/**
* @brief Bluetooth Mesh Element
* @defgroup bt_mesh_elem Bluetooth Mesh Element
* @ingroup bt_comp
* @{
*/
/** Helper to define a mesh element within an array.
*
* @param _loc Location Descriptor.
* @param _mods Array of models
* @param _vnd_mods Array of vendor models.
*/
#define BT_MESH_ELEM(_loc, _mods, _vnd_mods) \
{ \
.loc = (_loc), \
.model_count = ARRAY_SIZE(_mods), \
.models = (_mods), \
.vnd_model_count = ARRAY_SIZE(_vnd_mods), \
.vnd_models = (_vnd_mods), \
}
/** Abstraction that describes a Mesh Element */
struct bt_mesh_elem
{
/* Unicast Address. Set at runtime during provisioning. */
u16_t addr;
/* Location Descriptor (GATT Bluetooth Namespace Descriptors) */
const u16_t loc;
const u8_t model_count;
const u8_t vnd_model_count;
struct bt_mesh_model * const models;
struct bt_mesh_model * const vnd_models;
};
/**
* @}
*/
/**
* @brief Bluetooth Mesh Model
* @defgroup bt_mesh_model Bluetooth Mesh Model
* @ingroup bt_comp
* @{
*/
/* Foundation Models */
#define BT_MESH_MODEL_ID_CFG_SRV 0x0000
#define BT_MESH_MODEL_ID_CFG_CLI 0x0001
#define BT_MESH_MODEL_ID_HEALTH_SRV 0x0002
#define BT_MESH_MODEL_ID_HEALTH_CLI 0x0003
/* Models from the Mesh Model Specification */
#define BT_MESH_MODEL_ID_GEN_ONOFF_SRV 0x1000
#define BT_MESH_MODEL_ID_GEN_ONOFF_CLI 0x1001
#define BT_MESH_MODEL_ID_GEN_LEVEL_SRV 0x1002
#define BT_MESH_MODEL_ID_GEN_LEVEL_CLI 0x1003
#define BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_SRV 0x1004
#define BT_MESH_MODEL_ID_GEN_DEF_TRANS_TIME_CLI 0x1005
#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SRV 0x1006
#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_SETUP_SRV 0x1007
#define BT_MESH_MODEL_ID_GEN_POWER_ONOFF_CLI 0x1008
#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SRV 0x1009
#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_SETUP_SRV 0x100a
#define BT_MESH_MODEL_ID_GEN_POWER_LEVEL_CLI 0x100b
#define BT_MESH_MODEL_ID_GEN_BATTERY_SRV 0x100c
#define BT_MESH_MODEL_ID_GEN_BATTERY_CLI 0x100d
#define BT_MESH_MODEL_ID_GEN_LOCATION_SRV 0x100e
#define BT_MESH_MODEL_ID_GEN_LOCATION_SETUPSRV 0x100f
#define BT_MESH_MODEL_ID_GEN_LOCATION_CLI 0x1010
#define BT_MESH_MODEL_ID_GEN_ADMIN_PROP_SRV 0x1011
#define BT_MESH_MODEL_ID_GEN_MANUFACTURER_PROP_SRV 0x1012
#define BT_MESH_MODEL_ID_GEN_USER_PROP_SRV 0x1013
#define BT_MESH_MODEL_ID_GEN_CLIENT_PROP_SRV 0x1014
#define BT_MESH_MODEL_ID_GEN_PROP_CLI 0x1015
#define BT_MESH_MODEL_ID_SENSOR_SRV 0x1100
#define BT_MESH_MODEL_ID_SENSOR_SETUP_SRV 0x1101
#define BT_MESH_MODEL_ID_SENSOR_CLI 0x1102
#define BT_MESH_MODEL_ID_TIME_SRV 0x1200
#define BT_MESH_MODEL_ID_TIME_SETUP_SRV 0x1201
#define BT_MESH_MODEL_ID_TIME_CLI 0x1202
#define BT_MESH_MODEL_ID_SCENE_SRV 0x1203
#define BT_MESH_MODEL_ID_SCENE_SETUP_SRV 0x1204
#define BT_MESH_MODEL_ID_SCENE_CLI 0x1205
#define BT_MESH_MODEL_ID_SCHEDULER_SRV 0x1206
#define BT_MESH_MODEL_ID_SCHEDULER_SETUP_SRV 0x1207
#define BT_MESH_MODEL_ID_SCHEDULER_CLI 0x1208
#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV 0x1300
#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SETUP_SRV 0x1301
#define BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_CLI 0x1302
#define BT_MESH_MODEL_ID_LIGHT_CTL_SRV 0x1303
#define BT_MESH_MODEL_ID_LIGHT_CTL_SETUP_SRV 0x1304
#define BT_MESH_MODEL_ID_LIGHT_CTL_CLI 0x1305
#define BT_MESH_MODEL_ID_LIGHT_CTL_TEMP_SRV 0x1306
#define BT_MESH_MODEL_ID_LIGHT_HSL_SRV 0x1307
#define BT_MESH_MODEL_ID_LIGHT_HSL_SETUP_SRV 0x1308
#define BT_MESH_MODEL_ID_LIGHT_HSL_CLI 0x1309
#define BT_MESH_MODEL_ID_LIGHT_HSL_HUE_SRV 0x130a
#define BT_MESH_MODEL_ID_LIGHT_HSL_SAT_SRV 0x130b
#define BT_MESH_MODEL_ID_LIGHT_XYL_SRV 0x130c
#define BT_MESH_MODEL_ID_LIGHT_XYL_SETUP_SRV 0x130d
#define BT_MESH_MODEL_ID_LIGHT_XYL_CLI 0x130e
#define BT_MESH_MODEL_ID_LIGHT_LC_SRV 0x130f
#define BT_MESH_MODEL_ID_LIGHT_LC_SETUPSRV 0x1310
#define BT_MESH_MODEL_ID_LIGHT_LC_CLI 0x1311
/** Message sending context. */
struct bt_mesh_msg_ctx
{
/** NetKey Index of the subnet to send the message on. */
u16_t net_idx;
/** AppKey Index to encrypt the message with. */
u16_t app_idx;
/** Remote address. */
u16_t addr;
/** Received TTL value. Not used for sending. */
u8_t recv_ttl :7;
/** Whether friend credentials are used. */
u8_t friend_cred :1;
/** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */
u8_t send_ttl;
};
struct bt_mesh_model_op
{
/* OpCode encoded using the BT_MESH_MODEL_OP_* macros */
const u32_t opcode;
/* Minimum required message length */
const size_t min_len;
/* Message handler for the opcode */
void
(* const func)(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf);
};
#define BT_MESH_MODEL_OP_1(b0) (b0)
#define BT_MESH_MODEL_OP_2(b0, b1) (((b0) << 8) | (b1))
#define BT_MESH_MODEL_OP_3(b0, cid) ((((b0) << 16) | 0xc00000) | (cid))
#define BT_MESH_MODEL_OP_END { 0, 0, NULL }
#define BT_MESH_MODEL_NO_OPS ((struct bt_mesh_model_op []) \
{ BT_MESH_MODEL_OP_END })
/** Helper to define an empty model array */
#define BT_MESH_MODEL_EMPTY ((struct bt_mesh_model []){})
#define BT_MESH_MODEL(_id, _op, _pub, _user_data) \
{ \
.id = (_id), \
.op = _op, \
.keys = { [0 ... (MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT) - 1)] = \
BT_MESH_KEY_UNUSED }, \
.pub = _pub, \
.groups = { [0 ... (MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT) - 1)] = \
BT_MESH_ADDR_UNASSIGNED }, \
.user_data = _user_data, \
}
#define BT_MESH_MODEL_VND(_company, _id, _op, _pub, _user_data) \
{ \
.vnd.company = (_company), \
.vnd.id = (_id), \
.op = _op, \
.pub = _pub, \
.keys = { [0 ... (MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT) - 1)] = \
BT_MESH_KEY_UNUSED }, \
.groups = { [0 ... (MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT) - 1)] = \
BT_MESH_ADDR_UNASSIGNED }, \
.user_data = _user_data, \
}
/** Mesh Configuration Server Model Context */
struct bt_mesh_cfg
{
struct bt_mesh_model *model;
u8_t net_transmit; /* Network Transmit state */
u8_t relay; /* Relay Mode state */
u8_t relay_retransmit; /* Relay Retransmit state */
u8_t beacon; /* Secure Network Beacon state */
u8_t gatt_proxy; /* GATT Proxy state */
u8_t frnd; /* Friend state */
u8_t default_ttl; /* Default TTL */
/* Heartbeat Publication */
struct
{
struct k_delayed_work timer;
u16_t dst;u16_t count;u8_t period;u8_t ttl;u16_t feat;u16_t net_idx;
} hb_pub;
/* Heartbeat Subscription */
struct
{
s64_t expiry;
u16_t src;u16_t dst;u16_t count;u8_t min_hops;u8_t max_hops;
/* Optional subscription tracking function */
void
(*func)(u8_t hops, u16_t feat);
} hb_sub;
};
extern const struct bt_mesh_model_op bt_mesh_cfg_op[];
#define BT_MESH_MODEL_CFG_SRV(srv_data) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_CFG_SRV, \
bt_mesh_cfg_op, NULL, srv_data)
/** @def BT_MESH_TRANSMIT
*
* @brief Encode transmission count & interval steps.
*
* @param count Number of retransmissions (first transmission is excluded).
* @param int_ms Interval steps in milliseconds. Must be greater than 0
* and a multiple of 10.
*
* @return Mesh transmit value that can be used e.g. for the default
* values of the configuration model data.
*/
#define BT_MESH_TRANSMIT(count, int_ms) ((count) | (((int_ms / 10) - 1) << 3))
/** Mesh Health Server Model Context */
struct bt_mesh_health
{
struct bt_mesh_model *model;
/* Health Period (divider) */
u8_t period;
/* Fetch current faults */
int
(*fault_get_cur)(struct bt_mesh_model *model, u8_t *test_id,
u16_t *company_id,
u8_t *faults,
u8_t *fault_count);
/* Fetch registered faults */
int
(*fault_get_reg)(struct bt_mesh_model *model, u16_t company_id,
u8_t *test_id,
u8_t *faults,
u8_t *fault_count);
/* Clear registered faults */
int
(*fault_clear)(struct bt_mesh_model *model, u16_t company_id);
/* Run a specific test */
int
(*fault_test)(struct bt_mesh_model *model, u8_t test_id,
u16_t company_id);
/* Attention Timer state */
struct
{
struct k_delayed_work timer;
void
(*on)(struct bt_mesh_model *model);
void
(*off)(struct bt_mesh_model *model);
} attention;
};
int
bt_mesh_fault_update(struct bt_mesh_elem *elem);
extern const struct bt_mesh_model_op bt_mesh_health_op[];
extern struct bt_mesh_model_pub bt_mesh_health_pub;
#define BT_MESH_MODEL_HEALTH_SRV(srv_data) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_HEALTH_SRV, \
bt_mesh_health_op, &bt_mesh_health_pub, \
srv_data)
struct bt_mesh_model_pub
{
/* Self-reference for easy lookup */
struct bt_mesh_model *mod;
u16_t addr; /* Publish Address */
u16_t key; /* Publish AppKey Index */
u32_t ttl :8, /* Publish Time to Live */
retransmit :8, /* Retransmit Count & Interval Steps */
period :8, /* Publish Period */
period_div :4, /* Divisor for the Period */
cred :1; /* Friendship Credentials Flag */
/* Publish callback */
void
(*func)(struct bt_mesh_model *mod);
/* Publish Period Timer */
struct k_delayed_work timer;
};
/** Abstraction that describes a Mesh Model instance */
struct bt_mesh_model
{
union
{
const u16_t id;
struct
{
u16_t company;u16_t id;
} vnd;
};
/* The Element this Model belongs to */
struct bt_mesh_elem *elem;
/* Model Publication */
struct bt_mesh_model_pub * const pub;
/* AppKey List */
u16_t keys[MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT)];
/* Subscription List (group or virtual addresses) */
u16_t groups[MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT)];
const struct bt_mesh_model_op * const op;
/* Model-specific user data */
void *user_data;
};
typedef void
(*bt_mesh_cb_t)(int err, void *cb_data);
void
bt_mesh_model_msg_init(struct os_mbuf *msg, u32_t opcode);
/** Special TTL value to request using configured default TTL */
#define BT_MESH_TTL_DEFAULT 0xff
/** Maximum allowed TTL value */
#define BT_MESH_TTL_MAX 0x7f
/**
* @brief Send an Access Layer message.
*
* @param model Mesh (client) Model that the message belongs to.
* @param ctx Message context, includes keys, TTL, etc.
* @param msg Access Layer payload (the actual message to be sent).
* @param cb Optional "message sent" callback.
* @param cb_data User data to be passed to the callback.
*
* @return 0 on success, or (negative) error code on failure.
*/
int
bt_mesh_model_send(struct bt_mesh_model *model, struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *msg, bt_mesh_cb_t cb, void *cb_data);
/**
* @brief Send a model publication message.
*
* @param model Mesh (client) Model that's publishing the message.
* @param msg Access Layer message to publish.
*
* @return 0 on success, or (negative) error code on failure.
*/
int
bt_mesh_model_publish(struct bt_mesh_model *model, struct os_mbuf *msg);
/**
* @}
*/
/** Node Composition */
struct bt_mesh_comp
{
u16_t cid;u16_t pid;u16_t vid;
size_t elem_count;
struct bt_mesh_elem *elem;
};
/**
* @}
*/
/**
* @brief Bluetooth Mesh Provisioning
* @defgroup bt_mesh_prov Bluetooth Mesh Provisioning
* @ingroup bt_mesh
* @{
*/
typedef enum
{
BT_MESH_NO_OUTPUT = 0,
BT_MESH_BLINK = BIT(0),
BT_MESH_BEEP = BIT(1),
BT_MESH_VIBRATE = BIT(2),
BT_MESH_DISPLAY_NUMBER = BIT(3),
BT_MESH_DISPLAY_STRING = BIT(4),
} bt_mesh_output_action;
typedef enum
{
BT_MESH_NO_INPUT = 0,
BT_MESH_PUSH = BIT(0),
BT_MESH_TWIST = BIT(1),
BT_MESH_ENTER_NUMBER = BIT(2),
BT_MESH_ENTER_STRING = BIT(3),
} bt_mesh_input_action;
struct bt_mesh_prov
{
const u8_t *uuid;
u8_t *static_val;u8_t static_val_len;
u8_t output_size;u16_t output_actions;
u8_t input_size;u16_t input_actions;
int
(*output_number)(bt_mesh_output_action act, u32_t num);
int
(*output_string)(const char *str);
int
(*input)(bt_mesh_input_action act, u8_t size);
void
(*complete)(void);
};
int
bt_mesh_input_string(const char *str);
int
bt_mesh_input_number(u32_t num);
/**
* @}
*/
/**
* @brief Bluetooth Mesh
* @defgroup bt_mesh Bluetooth Mesh
* @ingroup bluetooth
* @{
*/
/* Primary Network Key index */
#define BT_MESH_NET_PRIMARY 0x000
#define BT_MESH_RELAY_DISABLED 0x00
#define BT_MESH_RELAY_ENABLED 0x01
#define BT_MESH_RELAY_NOT_SUPPORTED 0x02
#define BT_MESH_BEACON_DISABLED 0x00
#define BT_MESH_BEACON_ENABLED 0x01
#define BT_MESH_GATT_PROXY_DISABLED 0x00
#define BT_MESH_GATT_PROXY_ENABLED 0x01
#define BT_MESH_GATT_PROXY_NOT_SUPPORTED 0x02
#define BT_MESH_FRIEND_DISABLED 0x00
#define BT_MESH_FRIEND_ENABLED 0x01
#define BT_MESH_FRIEND_NOT_SUPPORTED 0x02
#define BT_MESH_NODE_IDENTITY_STOPPED 0x00
#define BT_MESH_NODE_IDENTITY_RUNNING 0x01
#define BT_MESH_NODE_IDENTITY_NOT_SUPPORTED 0x02
/* Features */
#define BT_MESH_FEAT_RELAY BIT(0)
#define BT_MESH_FEAT_PROXY BIT(1)
#define BT_MESH_FEAT_FRIEND BIT(2)
#define BT_MESH_FEAT_LOW_POWER BIT(3)
/** @brief Initialize Mesh support
*
* @param own_addr_type Node address type
* @param prov Node provisioning information.
* @param comp Node Composition.
*
* @return Zero on success or (negative) error code otherwise.
*/
int
bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov,
const struct bt_mesh_comp *comp);
/** @brief Reset the state of the local Mesh node.
*
* Resets the state of the node, which in turn causes it to start sending
* out unprovisioned beacons.
*/
void
bt_mesh_reset(void);
/** @brief Provision the local Mesh Node.
*
* This API should normally not be used directly by the application. The
* only exception is for testing purposes where manual provisioning is
* desired without an actual external provisioner.
*
* @param net_key Network Key
* @param net_idx Network Key Index
* @param flags Provisioning Flags
* @param iv_index IV Index
* @param seq Sequence Number (0 if newly provisioned).
* @param addr Primary element address
* @param dev_key Device Key
*
* @return Zero on success or (negative) error code otherwise.
*/
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]);
/** @brief Toggle the Low Power feature of the local device
*
* Enables or disables the Low Power feature of the local device. This is
* exposed as a run-time feature, since the device might want to change
* this e.g. based on being plugged into a stable power source or running
* from a battery power source.
*
* @param enable true to enable LPN functionality, false to disable it.
*
* @return Zero on success or (negative) error code otherwise.
*/
int
bt_mesh_lpn_set(bool enable);
/**
* @}
*/
#endif /* __BT_MESH_H */
+38
View File
@@ -0,0 +1,38 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
pkg.name: net/nimble/host/mesh
pkg.description: Bluetooth Mesh
pkg.author: "Apache Mynewt <[email protected]>"
pkg.homepage: "http://mynewt.apache.org/"
pkg.keywords:
- ble
- bluetooth
- mesh
pkg.deps:
- kernel/os
- net/nimble
- util/mem
- net/nimble/host
- crypto/tinycrypt
pkg.req_apis:
- log
- stats
+533
View File
@@ -0,0 +1,533 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <os/os_mbuf.h>
#include "mesh/mesh.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_ACCESS))
#include "host/ble_hs_log.h"
#include "mesh_priv.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);
} const model_init[] = {
{ BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_conf_init },
{ BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_init },
};
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 void mod_publish(struct os_event *work)
{
struct bt_mesh_model_pub *pub = work->ev_arg;
s32_t period_ms;
BT_DBG("");
if (pub->func) {
pub->func(pub->mod);
}
period_ms = bt_mesh_model_pub_period_get(pub->mod);
BT_DBG("period %u ms", period_ms);
if (period_ms) {
k_delayed_work_submit(&pub->timer, period_ms);
}
}
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 os_mbuf *buf, u32_t *opcode)
{
switch (buf->om_data[0] >> 6) {
case 0x00:
case 0x01:
if (buf->om_data[0] == 0x7f) {
BT_ERR("Ignoring RFU OpCode");
return -EINVAL;
}
*opcode = net_buf_simple_pull_u8(buf);
return 0;
case 0x02:
if (buf->om_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->om_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 os_mbuf *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->om_len, bt_hex(buf->om_data, buf->om_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->om_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 os_mbuf *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);
}
int bt_mesh_model_send(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *msg, bt_mesh_cb_t cb,
void *cb_data)
{
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(ctx->net_idx),
.ctx = ctx,
.src = model->elem->addr,
};
if (ctx->friend_cred && !bt_mesh_lpn_established()) {
BT_ERR("Friendship Credentials requested without a Friend");
return -EINVAL;
}
BT_DBG("net_idx 0x%04x app_idx 0x%04x dst 0x%04x", ctx->net_idx,
ctx->app_idx, ctx->addr);
BT_DBG("len %u: %s", msg->om_len, bt_hex(msg->om_data, msg->om_len));
if (net_buf_simple_tailroom(msg) < 4) {
BT_ERR("Not enough tailroom for TransMIC");
return -EINVAL;
}
if (msg->om_len > BT_MESH_TX_SDU_MAX - 4) {
BT_ERR("Too big message");
return -EMSGSIZE;
}
if (!model_has_key(model, ctx->app_idx)) {
BT_ERR("Model not bound to AppKey 0x%04x", ctx->app_idx);
return -EINVAL;
}
return bt_mesh_trans_send(&tx, msg, cb, cb_data);
}
int bt_mesh_model_publish(struct bt_mesh_model *model,
struct os_mbuf *msg)
{
struct bt_mesh_app_key *key;
struct bt_mesh_msg_ctx ctx;
if (!model->pub) {
return -ENOTSUP;
}
if (model->pub->key == BT_MESH_KEY_UNUSED ||
model->pub->addr == BT_MESH_ADDR_UNASSIGNED) {
return -EADDRNOTAVAIL;
}
key = bt_mesh_app_key_find(model->pub->key);
if (!key) {
return -EADDRNOTAVAIL;
}
ctx.net_idx = key->net_idx;
ctx.app_idx = key->app_idx;
ctx.addr = model->pub->addr;
ctx.friend_cred = model->pub->cred;
ctx.send_ttl = model->pub->ttl;
return bt_mesh_model_send(model, &ctx, msg, NULL, NULL);
}
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;
}
+61
View File
@@ -0,0 +1,61 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ACCESS_H__
#define __ACCESS_H__
#include "mesh/mesh.h"
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 os_mbuf *buf);
int
bt_mesh_comp_register(const struct bt_mesh_comp *comp);
#endif
+348
View File
@@ -0,0 +1,348 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "mesh/mesh.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_ADV))
#include "host/ble_hs_log.h"
#include "host/ble_hs_adv.h"
#include "host/ble_gap.h"
#include "nimble/hci_common.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.
*/
#define ADV_STACK_SIZE 768
struct os_task adv_task;
static struct os_eventq adv_queue;
static uint8_t g_own_addr_type;
static os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE(
MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT),
BT_MESH_ADV_DATA_SIZE + BT_MESH_ADV_USER_DATA_SIZE)];
struct os_mbuf_pool adv_os_mbuf_pool;
static struct os_mempool adv_buf_mempool;
static const u8_t adv_type[] = {
[BT_MESH_ADV_PROV] = BLE_HS_ADV_TYPE_MESH_PROV,
[BT_MESH_ADV_DATA] = BLE_HS_ADV_TYPE_MESH_MESSAGE,
[BT_MESH_ADV_BEACON] = BLE_HS_ADV_TYPE_MESH_BEACON,
};
static inline void adv_sent(struct os_mbuf *buf, int err)
{
if (BT_MESH_ADV(buf)->busy) {
BT_MESH_ADV(buf)->busy = 0;
if (BT_MESH_ADV(buf)->sent) {
BT_MESH_ADV(buf)->sent(buf, err);
}
}
net_buf_unref(buf);
}
static inline void adv_send(struct os_mbuf *buf)
{
/* XXX: For BT5 we could have better adv interval */
const s32_t adv_int_min = ADV_INT_DEFAULT;
struct ble_gap_adv_params param = { 0 };
u16_t duration, adv_int;
struct bt_mesh_adv *adv = BT_MESH_ADV(buf);
struct bt_data ad;
int err;
adv_int = max(adv_int_min, adv->adv_int);
duration = (adv->count + 1) * (adv_int + 10);
BT_DBG("buf %p, type %u len %u:", buf, adv->type,
buf->om_len);
BT_DBG("count %u interval %ums duration %ums",
adv->count + 1, adv_int, duration);
ad.type = adv_type[BT_MESH_ADV(buf)->type];
ad.data_len = buf->om_len;
ad.data = buf->om_data;
param.itvl_min = ADV_INT(adv_int);
param.itvl_max = param.itvl_min;
param.conn_mode = BLE_GAP_CONN_MODE_NON;
err = bt_le_adv_start(&param, &ad, 1, NULL, 0);
adv_sent(buf, err);
if (err) {
BT_ERR("Advertising failed: err %d", err);
return;
}
BT_DBG("Advertising started. Sleeping %u ms", duration);
os_time_delay(OS_TICKS_PER_SEC * duration / 1000);
err = bt_le_adv_stop();
if (err) {
BT_ERR("Stopping advertising failed: err %d", err);
return;
}
BT_DBG("Advertising stopped");
}
static void
adv_thread(void *args)
{
static struct os_event *ev;
struct os_mbuf *adv_data;
struct bt_mesh_adv *adv;
#if (MYNEWT_VAL(BLE_MESH_PROXY))
s32_t timeout;
struct os_eventq *eventq_pool = &adv_queue;
#endif
BT_DBG("started");
while (1) {
#if (MYNEWT_VAL(BLE_MESH_PROXY))
ev = os_eventq_get_no_wait(&adv_queue);
while (!ev) {
timeout = bt_mesh_proxy_adv_start();
BT_DBG("Proxy Advertising up to %d ms", timeout);
// FIXME: should we redefine K_SECONDS macro instead in glue?
if (timeout != K_FOREVER) {
timeout = OS_TICKS_PER_SEC * timeout / 1000;
}
ev = os_eventq_poll(&eventq_pool, 1, timeout);
bt_mesh_proxy_adv_stop();
}
#else
ev = os_eventq_get(&adv_queue);
#endif
if (!ev || !ev->ev_arg) {
continue;
}
adv_data = ev->ev_arg;
adv = BT_MESH_ADV(adv_data);
/* busy == 0 means this was canceled */
if (adv->busy) {
adv_send(adv_data);
}
os_sched(NULL);
}
}
void bt_mesh_adv_update(void)
{
static struct os_event ev = { };
BT_DBG("");
os_eventq_put(&adv_queue, &ev);
}
struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit_count,
u8_t xmit_int, s32_t timeout)
{
struct os_mbuf *adv_data;
struct bt_mesh_adv *adv;
adv_data = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, sizeof(struct bt_mesh_adv));
if (!adv_data) {
return NULL;
}
adv = BT_MESH_ADV(adv_data);
memset(adv, 0, sizeof(*adv));
adv->type = type;
adv->count = xmit_count;
adv->adv_int = xmit_int;
adv->ref_cnt = 1;
adv->ev.ev_arg = adv_data;
return adv_data;
}
void bt_mesh_adv_send(struct os_mbuf *buf, bt_mesh_adv_func_t sent)
{
BT_DBG("buf %p, type 0x%02x len %u: %s", buf, BT_MESH_ADV(buf)->type, buf->om_len,
bt_hex(buf->om_data, buf->om_len));
BT_MESH_ADV(buf)->sent = sent;
BT_MESH_ADV(buf)->busy = 1;
BT_MESH_ADV(buf)->ev.ev_cb = NULL; /* does not matter */
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 os_mbuf *buf)
{
if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
return;
}
BT_DBG("len %u: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
while (buf->om_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->om_len || buf->om_len < 1) {
BT_WARN("AD malformed");
return;
}
net_buf_simple_save(buf, &state);
type = net_buf_simple_pull_u8(buf);
switch (type) {
case BLE_HS_ADV_TYPE_MESH_MESSAGE:
bt_mesh_net_recv(buf, rssi, BT_MESH_NET_IF_ADV);
break;
#if MYNEWT_VAL(BLE_MESH_PB_ADV)
case BLE_HS_ADV_TYPE_MESH_PROV:
bt_mesh_pb_adv_recv(buf);
break;
#endif
case BLE_HS_ADV_TYPE_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(uint8_t own_addr_type)
{
os_stack_t *pstack;
int rc;
pstack = malloc(sizeof(os_stack_t) * ADV_STACK_SIZE);
assert(pstack);
g_own_addr_type = own_addr_type;
rc = os_mempool_init(&adv_buf_mempool, MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT),
BT_MESH_ADV_DATA_SIZE + BT_MESH_ADV_USER_DATA_SIZE,
adv_buf_mem, "adv_buf_pool");
assert(rc == 0);
rc = os_mbuf_pool_init(&adv_os_mbuf_pool, &adv_buf_mempool,
BT_MESH_ADV_DATA_SIZE + BT_MESH_ADV_USER_DATA_SIZE,
MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT));
assert(rc == 0);
os_eventq_init(&adv_queue);
os_task_init(&adv_task, "mesh_adv", adv_thread, NULL,
MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER, pstack,
ADV_STACK_SIZE);
}
int
ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg)
{
#if MYNEWT_VAL(BLE_EXT_ADV)
struct ble_gap_ext_disc_desc *ext_desc;
#endif
struct ble_gap_disc_desc *desc;
struct os_mbuf *buf = NULL;
BT_DBG("event->type %d", event->type);
switch (event->type) {
#if MYNEWT_VAL(BLE_EXT_ADV)
case BLE_GAP_EVENT_EXT_DISC:
ext_desc = &event->ext_disc;
buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
if (!buf || os_mbuf_append(buf, ext_desc->data, ext_desc->length_data)) {
BT_ERR("Could not append data");
goto done;
}
bt_mesh_scan_cb(&ext_desc->addr, ext_desc->rssi,
ext_desc->legacy_event_type, buf);
break;
#endif
case BLE_GAP_EVENT_DISC:
desc = &event->disc;
buf = os_mbuf_get_pkthdr(&adv_os_mbuf_pool, 0);
if (!buf || os_mbuf_append(buf, desc->data, desc->length_data)) {
BT_ERR("Could not append data");
goto done;
}
bt_mesh_scan_cb(&desc->addr, desc->rssi, desc->event_type, buf);
break;
default:
break;
}
done:
if (buf) {
os_mbuf_free_chain(buf);
}
return 0;
}
int bt_mesh_scan_enable(void)
{
struct ble_gap_disc_params scan_param =
{ .passive = 1, .filter_duplicates = 0, .itvl =
MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW };
BT_DBG("");
return ble_gap_disc(g_own_addr_type, BLE_HS_FOREVER, &scan_param, NULL, NULL);
}
int bt_mesh_scan_disable(void)
{
BT_DBG("");
return ble_gap_disc_cancel();
}
+67
View File
@@ -0,0 +1,67 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __ADV_H__
#define __ADV_H__
/* Maximum advertising data payload for a single data type */
#include "mesh/mesh.h"
#define BT_MESH_ADV_DATA_SIZE 31
#define BT_MESH_ADV_USER_DATA_SIZE (sizeof(struct os_mbuf_pkthdr) + \
sizeof(struct bt_mesh_adv)) + \
sizeof(struct os_mbuf)
#define BT_MESH_ADV(om) ((struct bt_mesh_adv *) OS_MBUF_USRHDR(om))
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 os_mbuf *adv_data, int err);
struct bt_mesh_adv
{
bt_mesh_adv_func_t sent;
u8_t type :2, busy :1;
u8_t count :3, adv_int :5;
union
{
/* Generic User Data */
u8_t user_data[2];
/* For transport layer segment sending */
struct
{
u8_t tx_id;
u8_t attempts :6, new_key :1, friend_cred :1;
} seg;
};
int ref_cnt;
struct os_event ev;
};
/* xmit_count: Number of retransmissions, i.e. 0 == 1 transmission */
struct os_mbuf * bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit_count,
u8_t xmit_int, s32_t timeout);
void bt_mesh_adv_send(struct os_mbuf *buf, bt_mesh_adv_func_t sent);
void bt_mesh_adv_update(void);
void bt_mesh_adv_init(uint8_t own_addr_type);
int bt_mesh_scan_enable(void);
int bt_mesh_scan_disable(void);
int ble_adv_gap_mesh_cb(struct ble_gap_event *event, void *arg);
#endif
+387
View File
@@ -0,0 +1,387 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <assert.h>
#include "os/os_mbuf.h"
#include "mesh/mesh.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_BEACON))
#include "host/ble_hs_log.h"
#include "adv.h"
#include <mesh_priv.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 {
u16_t net_idx;
u8_t data[21];
} beacon_cache[MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)];
static struct bt_mesh_subnet *cache_check(u8_t data[21])
{
struct bt_mesh_subnet *sub;
int i;
for (i = 0; i < ARRAY_SIZE(beacon_cache); i++) {
if (memcmp(beacon_cache[i].data, data, 21)) {
continue;
}
sub = bt_mesh_subnet_get(beacon_cache[i].net_idx);
if (sub) {
BT_DBG("Match found in cache");
return sub;
}
}
return NULL;
}
static void cache_add(u8_t data[21], u16_t net_idx)
{
memcpy(beacon_cache[net_idx].data, data, 21);
}
static void beacon_complete(struct os_mbuf *buf, int err)
{
struct bt_mesh_subnet *sub;
BT_DBG("err %d", err);
sub = &bt_mesh.sub[BT_MESH_ADV(buf)->user_data[0]];
sub->beacon_sent = k_uptime_get();
}
#define BEACON_INTERVAL(sub) K_SECONDS(10 * ((sub)->beacons_last + 1))
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
struct os_mbuf *buf)
{
struct bt_mesh_subnet_keys *keys;
u8_t flags;
net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE);
if (sub->kr_flag) {
flags = BT_MESH_NET_FLAG_KR;
keys = &sub->keys[1];
} else {
flags = 0x00;
keys = &sub->keys[0];
}
if (bt_mesh.iv_update) {
flags |= BT_MESH_NET_FLAG_IVU;
}
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));
}
static int secure_beacon_send(void)
{
s64_t threshold;
int i;
BT_DBG("");
/* If the interval has passed or is within 5 seconds from now
* send a beacon.
*/
threshold = k_uptime_get() + K_SECONDS(5);
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
struct os_mbuf *buf;
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (sub->beacon_sent + BEACON_INTERVAL(sub) > threshold) {
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_ADV(buf)->user_data[0] = i;
bt_mesh_beacon_create(sub, buf);
bt_mesh_adv_send(buf, beacon_complete);
net_buf_unref(buf);
}
return 0;
}
static int unprovisioned_beacon_send(void)
{
#if (MYNEWT_VAL(BLE_MESH_PB_ADV))
struct os_mbuf *buf;
BT_DBG("unprovisioned_beacon_send");
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) */
net_buf_add_zeros(buf, 2 + 4);
bt_mesh_adv_send(buf, NULL);
net_buf_unref(buf);
#endif /* MYNEWT_VAL(BLE_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 os_event *work)
{
/* Don't send anything if we have an active provisioning link */
if ((MYNEWT_VAL(BLE_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 os_mbuf *buf)
{
u8_t *data, *net_id, *auth;
struct bt_mesh_subnet *sub;
u32_t iv_index;
u8_t flags;
bool new_key;
if (buf->om_len < 21) {
BT_ERR("Too short secure beacon (len %u)", buf->om_len);
return;
}
sub = cache_check(buf->om_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->om_data;
flags = net_buf_simple_pull_u8(buf);
net_id = buf->om_data;
net_buf_simple_pull(buf, 8);
iv_index = net_buf_simple_pull_be32(buf);
auth = buf->om_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->net_idx);
/* 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);
}
bt_mesh_iv_update(iv_index, BT_MESH_IV_UPDATE(flags));
if (bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(flags), new_key)) {
bt_mesh_net_beacon_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 os_mbuf *buf)
{
u8_t type;
BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
if (buf->om_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);
/* Start beaconing since we're unprovisioned */
k_work_submit(&beacon_timer.work);
}
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);
}
}
+31
View File
@@ -0,0 +1,31 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __BEACON_H__
#define __BEACON_H__
#include "os/os_mbuf.h"
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 os_mbuf *buf);
void
bt_mesh_beacon_create(struct bt_mesh_subnet *sub, struct os_mbuf *buf);
void
bt_mesh_beacon_init(void);
#endif
File diff suppressed because it is too large Load Diff
+869
View File
@@ -0,0 +1,869 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <stdbool.h>
#include <errno.h>
#include <tinycrypt/constants.h>
#include <tinycrypt/utils.h>
#include <tinycrypt/aes.h>
#include <tinycrypt/cmac_mode.h>
#include <tinycrypt/ccm_mode.h>
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_CRYPTO))
#include "host/ble_hs_log.h"
#include "crypto.h"
#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 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 (MYNEWT_VAL(BLE_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 os_mbuf *buf,
u32_t iv_index, bool proxy)
{
u8_t mic_len = NET_MIC_LEN(buf->om_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->om_len, bt_hex(buf->om_data, buf->om_len));
#if (MYNEWT_VAL(BLE_MESH_PROXY))
if (proxy) {
create_proxy_nonce(nonce, buf->om_data, iv_index);
} else {
create_net_nonce(nonce, buf->om_data, iv_index);
}
#else
create_net_nonce(nonce, buf->om_data, iv_index);
#endif
BT_DBG("Nonce %s", bt_hex(nonce, 13));
err = bt_mesh_ccm_encrypt(key, nonce, &buf->om_data[7], buf->om_len - 7,
NULL, 0, &buf->om_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 os_mbuf *buf,
u32_t iv_index, bool proxy)
{
u8_t mic_len = NET_MIC_LEN(buf->om_data);
u8_t nonce[13];
BT_DBG("PDU (%u bytes) %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
BT_DBG("iv_index %u, key %s mic_len %u", iv_index, bt_hex(key, 16),
mic_len);
#if (MYNEWT_VAL(BLE_MESH_PROXY))
if (proxy) {
create_proxy_nonce(nonce, buf->om_data, iv_index);
} else {
create_net_nonce(nonce, buf->om_data, iv_index);
}
#else
create_net_nonce(nonce, buf->om_data, iv_index);
#endif
BT_DBG("Nonce %s", bt_hex(nonce, 13));
buf->om_len -= mic_len;
return bt_mesh_ccm_decrypt(key, nonce, &buf->om_data[7], buf->om_len - 7,
NULL, 0, &buf->om_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 os_mbuf *buf, const u8_t *ad,
u8_t mic_len, 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 mic_len %u src 0x%04x dst 0x%04x", dev_key,
mic_len, src, dst);
BT_DBG("seq_num 0x%08x iv_index 0x%08x", seq_num, iv_index);
BT_DBG("Clear: %s", bt_hex(buf->om_data, buf->om_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->om_data, buf->om_len, ad,
ad ? 16 : 0, buf->om_data, mic_len);
if (!err) {
net_buf_simple_add(buf, mic_len);
BT_DBG("Encr: %s", bt_hex(buf->om_data, buf->om_len));
}
return err;
}
int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, u8_t mic_len,
struct os_mbuf *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->om_len, bt_hex(buf->om_data, buf->om_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->om_data, buf->om_len, ad,
ad ? 16 : 0, out->om_data, mic_len);
if (!err) {
net_buf_simple_add(out, buf->om_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 os_mbuf *buf, u8_t received_fcs)
{
const u8_t *data = buf->om_data;
u16_t data_len = buf->om_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;
}
+162
View File
@@ -0,0 +1,162 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#include "mesh/mesh.h"
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 os_mbuf *buf,
u32_t iv_index, bool proxy);
int bt_mesh_net_decrypt(const u8_t key[16], struct os_mbuf *buf,
u32_t iv_index, bool proxy);
int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, const u8_t *ad,
u8_t mic_len, 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 os_mbuf *buf, u8_t mic_len,
struct os_mbuf *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 os_mbuf *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]);
#endif
+152
View File
@@ -0,0 +1,152 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __FUNDATION_H__
#define __FUNDATION_H__
#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, 0x34)
#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_conf_init(struct bt_mesh_model *model, bool primary);
int
bt_mesh_health_init(struct bt_mesh_model *model, bool primary);
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);
/* Transmission count (N + 1) */
#define TRANSMIT_COUNT(transmit) (((transmit) & (u8_t)BIT_MASK(3)))
/* Returns transmission interval in milliseconds */
#define TRANSMIT_INT(transmit) ((((transmit) >> 3) + 1) * 10)
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);
#endif
+215
View File
@@ -0,0 +1,215 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH_FRIEND) == 1
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_FRIEND))
#include "host/ble_hs_log.h"
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "crypto.h"
#include "adv.h"
#include "net.h"
#include "transport.h"
#include "access.h"
#include "friend.h"
static int send_friend_update(void)
{
struct bt_mesh_msg_ctx ctx = {
.net_idx = bt_mesh.sub[0].net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = bt_mesh.frnd.lpn,
.send_ttl = 0,
.friend_cred = 1,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
};
struct bt_mesh_ctl_friend_update upd = {
.flags = 0,
.iv_index = sys_cpu_to_be32(bt_mesh.iv_index),
.md = !k_fifo_is_empty(&bt_mesh.frnd.queue),
};
BT_DBG("");
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_UPDATE, &upd,
sizeof(upd), NULL);
}
int bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
{
struct bt_mesh_ctl_friend_poll *msg = (void *)buf->om_data;
struct bt_mesh_friend *frnd = &bt_mesh.frnd;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Update");
return -EINVAL;
}
BT_DBG("msg->fsn 0x%02x frnd->fsn 0x%02x", msg->fsn, frnd->fsn);
if (msg->fsn != frnd->fsn) {
frnd->send_last = 1;
}
frnd->fsn++;
frnd->send_update = 1;
k_delayed_work_submit(&frnd->timer, frnd->recv_delay);
return 0;
}
static int send_friend_offer(s8_t rssi)
{
struct bt_mesh_msg_ctx ctx = {
.net_idx = bt_mesh.sub[0].net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = bt_mesh.frnd.lpn,
.send_ttl = 0,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
};
struct bt_mesh_ctl_friend_offer off = {
.recv_win = MYNEWT_VAL(BLE_MESH_FRIEND_RECV_WIN),
.queue_size = MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE),
.rssi = rssi,
.frnd_counter = bt_mesh.frnd.counter++,
};
BT_DBG("");
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_OFFER, &off,
sizeof(off), NULL);
}
int bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
{
struct bt_mesh_ctl_friend_req *msg = (void *)buf->om_data;
struct bt_mesh_friend *frnd = &bt_mesh.frnd;
struct bt_mesh_subnet *sub = rx->sub;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Request");
return -EINVAL;
}
frnd->lpn = rx->ctx.addr;
frnd->rssi = rx->rssi;
frnd->recv_delay = msg->recv_delay;
frnd->poll_to = (((u32_t)msg->poll_to[0] << 16) |
((u32_t)msg->poll_to[1] << 8) |
((u32_t)msg->poll_to[2]));
frnd->poll_to *= 100;
frnd->lpn_counter = sys_be16_to_cpu(msg->lpn_counter);
BT_DBG("LPN 0x%04x rssi %d recv_delay %u poll_to %ums",
frnd->lpn, frnd->rssi, frnd->recv_delay, frnd->poll_to);
bt_mesh_friend_cred_add(sub->net_idx, sub->keys[0].net, 0,
frnd->lpn, frnd->lpn_counter, frnd->counter);
frnd->send_offer = 1;
k_delayed_work_submit(&frnd->timer, K_MSEC(100));
return 0;
}
static void friend_timeout(struct os_event *work)
{
struct bt_mesh_friend *frnd = &bt_mesh.frnd;
BT_DBG("send_offer %u send_update %u", frnd->send_offer,
frnd->send_update);
if (frnd->send_offer) {
frnd->send_offer = 0;
send_friend_offer(frnd->rssi);
return;
}
if (!frnd->send_update) {
BT_WARN("Friendship lost");
bt_mesh_friend_cred_del(bt_mesh.sub[0].net_idx, frnd->lpn);
return;
}
frnd->send_update = 0;
if (frnd->send_last && frnd->last) {
frnd->send_last = 0;
bt_mesh_adv_send(frnd->last, NULL);
return;
}
if (frnd->last) {
net_buf_unref(frnd->last);
}
frnd->last = net_buf_get(&frnd->queue, K_NO_WAIT);
if (frnd->last) {
bt_mesh_adv_send(frnd->last, NULL);
} else {
send_friend_update();
}
k_delayed_work_submit(&frnd->timer, frnd->poll_to);
}
int bt_mesh_friend_init(void)
{
struct bt_mesh_friend *frnd = &bt_mesh.frnd;
k_fifo_init(&frnd->queue);
k_delayed_work_init(&frnd->timer, friend_timeout);
return 0;
}
bool bt_mesh_friend_enqueue(struct os_mbuf *buf, u16_t dst)
{
/* FIXME: Add support for multiple LPNs and group addresses */
if (!bt_mesh_friend_dst_is_lpn(dst)) {
return false;
}
if (BT_MESH_ADDR_IS_UNICAST(dst)) {
net_buf_put(&bt_mesh.frnd.queue, net_buf_ref(buf));
} else {
struct os_mbuf *clone = net_buf_clone(buf, K_NO_WAIT);
if (clone) {
net_buf_put(&bt_mesh.frnd.queue, clone);
} else {
BT_WARN("Unable to allocate buffer for friend queue");
return false;
}
}
BT_DBG("Queued message for LPN");
return true;
}
#endif //MYNEWT_VAL(BLE_MESH_FRIEND)
+35
View File
@@ -0,0 +1,35 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __FRIEND_H__
#define __FRIEND_H__
#include "mesh/mesh.h"
static inline bool
bt_mesh_friend_dst_is_lpn(u16_t dst)
{
#if (MYNEWT_VAL(BLE_MESH_FRIEND))
return (dst == bt_mesh.frnd.lpn);
#else
return false;
#endif
}
bool
bt_mesh_friend_enqueue(struct os_mbuf *buf, u16_t dst);
int
bt_mesh_friend_poll(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
int
bt_mesh_friend_req(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
int
bt_mesh_friend_init(void);
#endif
+486
View File
@@ -0,0 +1,486 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "mesh/glue.h"
#include "adv.h"
const char *
bt_hex(const void *buf, size_t len)
{
static const char hex[] = "0123456789abcdef";
static char hexbufs[4][137];
static u8_t curbuf;
const u8_t *b = buf;
char *str;
int i;
str = hexbufs[curbuf++];
curbuf %= ARRAY_SIZE(hexbufs);
len = min(len, (sizeof(hexbufs[0]) - 1) / 2);
for (i = 0; i < len; i++) {
str[i * 2] = hex[b[i] >> 4];
str[i * 2 + 1] = hex[b[i] & 0xf];
}
str[i * 2] = '\0';
return str;
}
void
net_buf_put(struct os_eventq *fifo, struct os_mbuf *om)
{
struct os_event *ev;
assert(OS_MBUF_IS_PKTHDR(om));
ev = &BT_MESH_ADV(om)->ev;
assert(ev);
assert(ev->ev_arg);
os_eventq_put(fifo, ev);
}
void *
net_buf_ref(struct os_mbuf *om)
{
struct bt_mesh_adv *adv;
/* For bufs with header we count refs*/
if (OS_MBUF_USRHDR_LEN(om) == 0) {
return NULL;
}
adv = BT_MESH_ADV(om);
adv->ref_cnt++;
return om;
}
void
net_buf_unref(struct os_mbuf *om)
{
struct bt_mesh_adv *adv;
/* For bufs with header we count refs*/
if (OS_MBUF_USRHDR_LEN(om) == 0) {
goto free;
}
adv = BT_MESH_ADV(om);
if (--adv->ref_cnt > 0) {
return;
}
free:
os_mbuf_free_chain(om);
}
int
bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data)
{
struct tc_aes_key_sched_struct s;
if (tc_aes128_set_encrypt_key(&s, key) == TC_CRYPTO_FAIL) {
return BLE_HS_EUNKNOWN;
}
if (tc_aes_encrypt(enc_data, plaintext, &s) == TC_CRYPTO_FAIL) {
return BLE_HS_EUNKNOWN;
}
return 0;
}
uint16_t
net_buf_simple_pull_le16(struct os_mbuf *om)
{
uint16_t val;
struct os_mbuf *old = om;
om = os_mbuf_pullup(om, sizeof(val));
assert(om == old);
val = get_le16(om->om_data);
os_mbuf_adj(om, sizeof(val));
return val;
}
uint16_t
net_buf_simple_pull_be16(struct os_mbuf *om)
{
uint16_t val;
struct os_mbuf *old = om;
om = os_mbuf_pullup(om, sizeof(val));
assert(om == old);
val = get_be16(om->om_data);
os_mbuf_adj(om, sizeof(val));
return val;
}
uint32_t
net_buf_simple_pull_be32(struct os_mbuf *om)
{
uint32_t val;
struct os_mbuf *old = om;
om = os_mbuf_pullup(om, sizeof(val));
assert(om == old);
val = get_be32(om->om_data);
os_mbuf_adj(om, sizeof(val));
return val;
}
uint8_t
net_buf_simple_pull_u8(struct os_mbuf *om)
{
uint8_t val;
struct os_mbuf *old = om;
om = os_mbuf_pullup(om, sizeof(val));
assert(om == old);
val = om->om_data[0];
os_mbuf_adj(om, 1);
return val;
}
void
net_buf_simple_add_le16(struct os_mbuf *om, uint16_t val)
{
val = htole16(val);
os_mbuf_append(om, &val, sizeof(val));
}
void
net_buf_simple_add_be16(struct os_mbuf *om, uint16_t val)
{
val = htobe16(val);
os_mbuf_append(om, &val, sizeof(val));
}
void
net_buf_simple_add_be32(struct os_mbuf *om, uint32_t val)
{
val = htobe32(val);
os_mbuf_append(om, &val, sizeof(val));
}
void
net_buf_simple_add_u8(struct os_mbuf *om, uint8_t val)
{
os_mbuf_append(om, &val, 1);
}
void
net_buf_simple_push_le16(struct os_mbuf *om, uint16_t val)
{
uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len];
assert(headroom >= 2);
om->om_data -= 2;
put_le16(om->om_data, val);
om->om_len += 2;
if (om->om_pkthdr_len) {
OS_MBUF_PKTHDR(om)->omp_len += 2;
}
}
void
net_buf_simple_push_be16(struct os_mbuf *om, uint16_t val)
{
uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len];
assert(headroom >= 2);
om->om_data -= 2;
put_be16(om->om_data, val);
om->om_len += 2;
if (om->om_pkthdr_len) {
OS_MBUF_PKTHDR(om)->omp_len += 2;
}
}
void
net_buf_simple_push_u8(struct os_mbuf *om, uint8_t val)
{
uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len];
assert(headroom >= 1);
om->om_data -= 1;
om->om_data[0] = val;
om->om_len += 1;
if (om->om_pkthdr_len) {
OS_MBUF_PKTHDR(om)->omp_len += 1;
}
}
void
net_buf_add_zeros(struct os_mbuf *om, uint8_t len)
{
uint8_t z[len];
int rc;
memset(z, 0, len);
rc = os_mbuf_append(om, z, len);
if(rc) {
assert(0);
}
}
void *
net_buf_simple_pull(struct os_mbuf *om, uint8_t len)
{
os_mbuf_adj(om, len);
return om->om_data;
}
void*
net_buf_simple_add(struct os_mbuf *om, uint8_t len)
{
return os_mbuf_extend(om, len);
}
bool
k_fifo_is_empty(struct os_eventq *q)
{
return STAILQ_EMPTY(&q->evq_list);
}
void * net_buf_get(struct os_eventq *fifo,s32_t t)
{
struct os_event *ev = os_eventq_get_no_wait(fifo);
return ev->ev_arg;
}
uint8_t *
net_buf_simple_push(struct os_mbuf *om, uint8_t len)
{
uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len];
assert(headroom >= len);
om->om_data -= len;
om->om_len += len;
return om->om_data;
}
void
net_buf_reserve(struct os_mbuf *om, size_t reserve)
{
/* We need reserve to be done on fresh buf */
assert(om->om_len == 0);
om->om_data += reserve;
}
void
k_work_init(struct os_callout *work, os_event_fn handler)
{
os_callout_init(work, os_eventq_dflt_get(), handler, NULL);
}
void
k_delayed_work_init(struct k_delayed_work *w, os_event_fn *f)
{
os_callout_init(&w->work, os_eventq_dflt_get(), f, NULL);
}
void
k_delayed_work_cancel(struct k_delayed_work *w)
{
os_callout_stop(&w->work);
}
void
k_delayed_work_submit(struct k_delayed_work *w, uint32_t ms)
{
uint32_t ticks;
os_time_ms_to_ticks(ms, &ticks);
os_callout_reset(&w->work, ticks);
}
void
k_work_submit(struct os_callout *w)
{
os_callout_reset(w, 0);
}
void
k_work_add_arg(struct os_callout *w, void *arg)
{
w->c_ev.ev_arg = arg;
}
void
k_delayed_work_add_arg(struct k_delayed_work *w, void *arg)
{
w->work.c_ev.ev_arg = arg;
}
uint32_t
k_delayed_work_remaining_get (struct k_delayed_work *w)
{
int sr;
os_time_t t;
OS_ENTER_CRITICAL(sr);
t = os_callout_remaining_ticks(&w->work, os_cputime_get32());
OS_EXIT_CRITICAL(sr);
/* We should return ms */
return os_cputime_ticks_to_usecs(t) / 1000;
}
int64_t k_uptime_get(void)
{
/* We should return ms */
return os_get_uptime_usec() / 1000;
}
u32_t k_uptime_get_32(void)
{
return k_uptime_get();
}
static uint8_t pub[64];
static uint32_t priv[8];
static bool has_pub = false;
int
bt_dh_key_gen(const u8_t remote_pk[64], bt_dh_key_cb_t cb)
{
uint8_t dh[32];
if (ble_sm_alg_gen_dhkey((uint8_t *)&remote_pk[0], (uint8_t *)&remote_pk[32],
priv, dh)) {
return -1;
}
cb(dh);
return 0;
}
int
bt_rand(void *buf, size_t len)
{
int rc;
rc = ble_hs_hci_util_rand(buf, len);
if (rc != 0) {
return -1;
}
return 0;
}
int
bt_pub_key_gen(struct bt_pub_key_cb *new_cb)
{
if (ble_sm_alg_gen_key_pair(pub, priv)) {
assert(0);
return -1;
}
new_cb->func(pub);
has_pub = true;
return 0;
}
uint8_t *
bt_pub_key_get(void)
{
if (!has_pub) {
return NULL;
}
return pub;
}
static int
set_ad(const struct bt_data *ad, size_t ad_len, u8_t *buf, u8_t *buf_len)
{
int i;
for (i = 0; i < ad_len; i++) {
buf[(*buf_len)++] = ad[i].data_len + 1;
buf[(*buf_len)++] = ad[i].type;
memcpy(&buf[*buf_len], ad[i].data,
ad[i].data_len);
*buf_len += ad[i].data_len;
}
return 0;
}
int
bt_le_adv_start(const struct ble_gap_adv_params *param,
const struct bt_data *ad, size_t ad_len,
const struct bt_data *sd, size_t sd_len)
{
#if MYNEWT_VAL(BLE_EXT_ADV)
uint8_t buf[MYNEWT_VAL(BLE_EXT_ADV_MAX_SIZE)];
#else
uint8_t buf[BLE_HS_ADV_MAX_SZ];
#endif
uint8_t buf_len = 0;
int err;
err = set_ad(ad, ad_len, buf, &buf_len);
if (err) {
return err;
}
err = ble_gap_adv_set_data(buf, buf_len);
if (err != 0) {
return err;
}
err = ble_gap_adv_start(0x00, NULL, BLE_HS_FOREVER, param, NULL, NULL);
if (err) {
BT_ERR("Advertising failed: err %d", err);
return err;
}
return 0;
}
#if MYNEWT_VAL(BLE_MESH_PROXY)
int bt_mesh_proxy_svcs_register(void);
#endif
void
bt_mesh_register_gatt(void)
{
#if MYNEWT_VAL(BLE_MESH_PROXY)
bt_mesh_proxy_svcs_register();
#endif
}
+451
View File
@@ -0,0 +1,451 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_MODEL))
#include "host/ble_hs_log.h"
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "adv.h"
#include "net.h"
#include "transport.h"
#include "access.h"
#include "foundation.h"
#define HEALTH_TEST_STANDARD 0x00
/* Increasing this requires also increasing the system workqueue */
#define MAX_FAULTS 32
#define HEALTH_STATUS_SIZE_MAX (1 + 3 + MAX_FAULTS + 4)
#if BT_MESH_TX_SDU_MAX < HEALTH_STATUS_SIZE_MAX
#define HEALTH_STATUS_SIZE BT_MESH_TX_SDU_MAX
#else
#define HEALTH_STATUS_SIZE HEALTH_STATUS_SIZE_MAX
#endif
/* Health Server context of the primary element */
struct bt_mesh_health *health_srv;
static void health_get_registered(struct bt_mesh_model *mod,
u16_t company_id,
struct os_mbuf *msg)
{
struct bt_mesh_health *srv = mod->user_data;
u8_t fault_count;
u8_t *test_id;
int err;
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);
fault_count = net_buf_simple_tailroom(msg) - 4;
if (srv->fault_get_reg) {
err = srv->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 os_mbuf *msg)
{
struct bt_mesh_health *srv = mod->user_data;
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));
fault_count = net_buf_simple_tailroom(msg) - 4;
if (srv->fault_get_cur) {
err = srv->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(0, company_ptr);
*test_id = HEALTH_TEST_STANDARD;
fault_count = 0;
} else {
sys_put_le16(company_id, company_ptr);
}
} else {
BT_WARN("No callback for getting faults");
net_buf_simple_push_u8(msg, HEALTH_TEST_STANDARD);
net_buf_simple_push_le16(msg, 0);
fault_count = 0;
}
return fault_count;
}
static void health_fault_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(HEALTH_STATUS_SIZE);
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, msg);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
BT_ERR("Unable to send Health Current Status response");
}
os_mbuf_free_chain(msg);
}
static void health_fault_clear_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct bt_mesh_health *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->fault_clear) {
srv->fault_clear(model, company_id);
}
}
static void health_fault_clear(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(HEALTH_STATUS_SIZE);
struct bt_mesh_health *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->fault_clear) {
srv->fault_clear(model, company_id);
}
health_get_registered(model, company_id, msg);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
BT_ERR("Unable to send Health Current Status response");
}
os_mbuf_free_chain(msg);
}
static void health_fault_test_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct bt_mesh_health *srv = model->user_data;
const struct bt_mesh_comp *comp;
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);
comp = bt_mesh_comp_get();
if (comp->cid != company_id) {
BT_WARN("CID 0x%04x doesn't match composition CID 0x%04x",
company_id, comp->cid);
return;
}
if (srv->fault_test) {
srv->fault_test(model, test_id, company_id);
}
}
static void health_fault_test(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(HEALTH_STATUS_SIZE);
struct bt_mesh_health *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->fault_test) {
srv->fault_test(model, test_id, company_id);
}
health_get_registered(model, company_id, msg);
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
BT_ERR("Unable to send Health Current Status response");
}
os_mbuf_free_chain(msg);
}
static void send_attention_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct bt_mesh_health *srv = model->user_data;
u8_t time;
time = k_delayed_work_remaining_get(&srv->attention.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);
bt_mesh_model_send(model, ctx, msg, NULL, NULL);
os_mbuf_free_chain(msg);
}
static void attention_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *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 os_mbuf *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 os_mbuf *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 os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct bt_mesh_health *srv = model->user_data;
bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_STATUS);
net_buf_simple_add_u8(msg, srv->period);
bt_mesh_model_send(model, ctx, msg, NULL, NULL);
os_mbuf_free_chain(msg);
}
static void health_period_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *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 os_mbuf *buf)
{
struct bt_mesh_health *srv = model->user_data;
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);
srv->period = period;
}
static void health_period_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *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_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 void health_pub(struct bt_mesh_model *mod)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(HEALTH_STATUS_SIZE);
struct bt_mesh_health *srv = mod->user_data;
size_t count;
int err;
BT_DBG("");
count = health_get_current(mod, msg);
if (count) {
mod->pub->period_div = srv->period;
} else {
mod->pub->period_div = 0;
}
err = bt_mesh_model_publish(mod, msg);
if (err) {
BT_ERR("Publishing failed (err %d)", err);
}
os_mbuf_free_chain(msg);
}
struct bt_mesh_model_pub bt_mesh_health_pub = {
.func = health_pub,
};
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;
}
k_delayed_work_submit(&mod->pub->timer, K_NO_WAIT);
return 0;
}
static void attention_off(struct os_event *work)
{
struct bt_mesh_health *srv = work->ev_arg;
BT_DBG("");
if (srv->attention.off) {
srv->attention.off(srv->model);
}
}
int bt_mesh_health_init(struct bt_mesh_model *model, bool primary)
{
struct bt_mesh_health *srv = model->user_data;
if (!srv) {
if (!primary) {
return 0;
}
BT_ERR("No Health Server context provided");
return -EINVAL;
}
k_delayed_work_init(&srv->attention.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;
BT_DBG("bt_mesh_attention");
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->attention.on) {
srv->attention.on(model);
}
k_delayed_work_submit(&srv->attention.timer, time * 1000);
} else {
k_delayed_work_cancel(&srv->attention.timer);
if (srv->attention.off) {
srv->attention.off(model);
}
}
}
+883
View File
@@ -0,0 +1,883 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH_LOW_POWER) == 1
#include <stdint.h>
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_LOW_POWER))
#include "host/ble_hs_log.h"
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "crypto.h"
#include "adv.h"
#include "net.h"
#include "transport.h"
#include "access.h"
#include "beacon.h"
#include "lpn.h"
#define LPN_RECV_DELAY MYNEWT_VAL(BLE_MESH_LPN_RECV_DELAY)
#define SCAN_LATENCY min(MYNEWT_VAL(BLE_MESH_LPN_SCAN_LATENCY), \
LPN_RECV_DELAY)
#define FRIEND_REQ_RETRY_TIMEOUT K_SECONDS(5)
#define FRIEND_REQ_TIMEOUT (K_MSEC(100) + K_SECONDS(1))
#define POLL_RETRY_TIMEOUT K_MSEC(100)
#define REQ_ATTEMPTS(lpn) ((lpn)->poll_timeout < K_SECONDS(3) ? 2 : 4)
#define REQ_RETRY_DURATION(lpn) (REQ_ATTEMPTS(lpn) * \
(LPN_RECV_DELAY + (lpn)->recv_win + \
POLL_RETRY_TIMEOUT))
#define POLL_TIMEOUT(lpn) ((MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT) * 100) - \
REQ_RETRY_DURATION(lpn))
#define LPN_CRITERIA ((MYNEWT_VAL(BLE_MESH_LPN_MIN_QUEUE_SIZE)) | \
(MYNEWT_VAL(BLE_MESH_LPN_RSSI_FACTOR) << 3) | \
(MYNEWT_VAL(BLE_MESH_LPN_RECV_WIN_FACTOR) << 5))
#define POLL_TO(to) { (u8_t)((to) >> 16), (u8_t)((to) >> 8), (u8_t)(to) }
#define LPN_POLL_TO POLL_TO(MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT))
#if (MYNEWT_VAL(BLE_MESH_DEBUG_LOW_POWER))
static const char *state2str(int state)
{
switch (state) {
case BT_MESH_LPN_DISABLED:
return "disabled";
case BT_MESH_LPN_CLEAR:
return "clear";
case BT_MESH_LPN_ENABLED:
return "enabled";
case BT_MESH_LPN_WAIT_OFFER:
return "wait offer";
case BT_MESH_LPN_ESTABLISHING:
return "establishing";
case BT_MESH_LPN_ESTABLISHED:
return "established";
case BT_MESH_LPN_RECV_DELAY:
return "recv delay";
case BT_MESH_LPN_WAIT_UPDATE:
return "wait update";
default:
return "(unknown)";
}
}
#endif /* CONFIG_BLUETOOTH_MESH_DEBUG_LPN */
static inline void lpn_set_state(int state)
{
#if (MYNEWT_VAL(BLE_MESH_DEBUG_LOW_POWER))
BT_DBG("%s -> %s", state2str(bt_mesh.lpn.state), state2str(state));
#endif
bt_mesh.lpn.state = state;
}
static void clear_friendship(bool disable);
static void friend_clear_sent(struct os_mbuf *buf, int err)
{
/* We're switching away from Low Power behavior, so permanently
* enable scanning.
*/
bt_mesh_scan_enable();
if (err) {
BT_ERR("Sending Friend Request failed (err %d)", err);
lpn_set_state(BT_MESH_LPN_ENABLED);
clear_friendship(bt_mesh.lpn.disable);
return;
}
lpn_set_state(BT_MESH_LPN_CLEAR);
k_delayed_work_submit(&bt_mesh.lpn.timer, FRIEND_REQ_TIMEOUT);
}
static int send_friend_clear(void)
{
struct bt_mesh_msg_ctx ctx = {
.net_idx = bt_mesh.sub[0].net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = bt_mesh.lpn.frnd,
.send_ttl = 0,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
};
struct bt_mesh_ctl_friend_clear req = {
.lpn_addr = sys_cpu_to_be16(tx.src),
.lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.counter),
};
BT_DBG("");
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req,
sizeof(req), friend_clear_sent);
}
static void clear_friendship(bool disable)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
if (lpn->state >= BT_MESH_LPN_ESTABLISHED) {
send_friend_clear();
lpn->disable = disable;
return;
}
bt_mesh_rx_reset();
k_delayed_work_cancel(&lpn->timer);
bt_mesh_friend_cred_del(bt_mesh.sub[0].net_idx, lpn->frnd);
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
lpn->fsn = 0;
lpn->req_attempts = 0;
lpn->recv_win = 0;
lpn->queue_size = 0;
lpn->disable = 0;
lpn->sent_req = 0;
/* Set this to 1 to force group subscription when the next
* Friendship is created, in case lpn->groups doesn't get
* modified meanwhile.
*/
lpn->groups_changed = 1;
if (disable) {
lpn_set_state(BT_MESH_LPN_DISABLED);
return;
}
lpn_set_state(BT_MESH_LPN_ENABLED);
k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT);
}
static void friend_req_sent(struct os_mbuf *buf, int err)
{
if (err) {
BT_ERR("Sending Friend Request failed (err %d)", err);
return;
}
lpn_set_state(BT_MESH_LPN_WAIT_OFFER);
k_delayed_work_submit(&bt_mesh.lpn.timer, FRIEND_REQ_TIMEOUT);
}
static int send_friend_req(void)
{
const struct bt_mesh_comp *comp = bt_mesh_comp_get();
struct bt_mesh_msg_ctx ctx = {
.net_idx = bt_mesh.sub[0].net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = BT_MESH_ADDR_FRIENDS,
.send_ttl = 0,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
};
struct bt_mesh_ctl_friend_req req = {
.criteria = LPN_CRITERIA,
.recv_delay = LPN_RECV_DELAY,
.poll_to = LPN_POLL_TO,
.prev_addr = BT_MESH_ADDR_UNASSIGNED,
.num_elem = comp->elem_count,
.lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.counter),
};
BT_DBG("");
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req,
sizeof(req), friend_req_sent);
}
static inline void group_zero(atomic_t *target)
{
#if CONFIG_BLUETOOTH_MESH_LPN_GROUPS > 32
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) {
atomic_set(&target[i], 0);
}
#else
atomic_set(target, 0);
#endif
}
static inline void group_set(atomic_t *target, atomic_t *source)
{
#if CONFIG_BLUETOOTH_MESH_LPN_GROUPS > 32
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) {
atomic_or(&target[i], atomic_get(&source[i]));
}
#else
atomic_or(target, atomic_get(source));
#endif
}
static inline void group_clear(atomic_t *target, atomic_t *source)
{
#if CONFIG_BLUETOOTH_MESH_LPN_GROUPS > 32
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) {
atomic_and(&target[i], ~atomic_get(&source[i]));
}
#else
atomic_and(target, ~atomic_get(source));
#endif
}
static void req_sent(struct os_mbuf *buf, int err)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
if (err) {
BT_ERR("Sending request failed (err %d)", err);
lpn->sent_req = 0;
group_zero(lpn->pending);
return;
}
lpn->req_attempts++;
if (lpn->state == BT_MESH_LPN_ESTABLISHING) {
k_delayed_work_submit(&lpn->timer,
LPN_RECV_DELAY + lpn->recv_win);
} else { /* Established Friendship */
lpn_set_state(BT_MESH_LPN_RECV_DELAY);
/* We start scanning a bit early to elimitate risk of missing
* response data due to HCI and other latencies.
*/
k_delayed_work_submit(&lpn->timer,
LPN_RECV_DELAY - SCAN_LATENCY);
}
}
static int send_friend_poll(void)
{
struct bt_mesh_msg_ctx ctx = {
.net_idx = bt_mesh.sub[0].net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = bt_mesh.lpn.frnd,
.send_ttl = 0,
.friend_cred = 1,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
};
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
u8_t fsn = lpn->fsn;
int err;
BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req);
if (lpn->sent_req) {
if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) {
lpn->pending_poll = 1;
}
return 0;
}
err = bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_POLL, &fsn, 1,
req_sent);
if (err == 0) {
lpn->pending_poll = 0;
lpn->sent_req = TRANS_CTL_OP_FRIEND_POLL;
}
return err;
}
void bt_mesh_lpn_disable(void)
{
if (bt_mesh.lpn.state == BT_MESH_LPN_DISABLED) {
return;
}
clear_friendship(true);
}
int bt_mesh_lpn_set(bool enable)
{
if (enable) {
if (bt_mesh.lpn.state != BT_MESH_LPN_DISABLED) {
return 0;
}
} else {
if (bt_mesh.lpn.state == BT_MESH_LPN_DISABLED) {
return 0;
}
}
if (!bt_mesh_is_provisioned()) {
if (enable) {
lpn_set_state(BT_MESH_LPN_ENABLED);
} else {
lpn_set_state(BT_MESH_LPN_DISABLED);
}
return 0;
}
if (enable) {
send_friend_req();
} else {
bt_mesh_lpn_disable();
}
return 0;
}
static void friend_response_received(struct bt_mesh_lpn *lpn)
{
BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req);
if (lpn->sent_req == TRANS_CTL_OP_FRIEND_POLL) {
lpn->fsn++;
}
k_delayed_work_cancel(&lpn->timer);
bt_mesh_scan_disable();
lpn_set_state(BT_MESH_LPN_ESTABLISHED);
lpn->req_attempts = 0;
lpn->sent_req = 0;
}
void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) {
BT_WARN("Unexpected message withouth a preceding Poll");
return;
}
friend_response_received(lpn);
BT_DBG("Requesting more messages from Friend");
send_friend_poll();
}
int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
struct os_mbuf *buf)
{
struct bt_mesh_ctl_friend_offer *msg = (void *)buf->om_data;
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
struct bt_mesh_subnet *sub = rx->sub;
struct bt_mesh_friend_cred *cred;
u16_t frnd_counter;
int err;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Offer");
return -EINVAL;
}
if (lpn->state != BT_MESH_LPN_WAIT_OFFER) {
BT_WARN("Ignoring unexpected Friend Offer");
return 0;
}
frnd_counter = sys_be16_to_cpu(msg->frnd_counter);
BT_DBG("recv_win %u queue_size %u sub_list_size %u rssi %d counter %u",
msg->recv_win, msg->queue_size, msg->sub_list_size, msg->rssi,
frnd_counter);
lpn->frnd = rx->ctx.addr;
cred = bt_mesh_friend_cred_add(sub->net_idx, sub->keys[0].net, 0,
lpn->frnd, lpn->counter, frnd_counter);
if (!cred) {
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
return -ENOMEM;
}
if (sub->kr_flag) {
err = bt_mesh_friend_cred_set(cred, 1, sub->keys[1].net);
if (err) {
bt_mesh_friend_cred_clear(cred);
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
return err;
}
}
/* TODO: Add offer acceptance criteria check */
k_delayed_work_cancel(&lpn->timer);
lpn->recv_win = msg->recv_win;
lpn->queue_size = msg->queue_size;
err = send_friend_poll();
if (err) {
bt_mesh_friend_cred_clear(cred);
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
lpn->recv_win = 0;
lpn->queue_size = 0;
return err;
}
lpn->counter++;
lpn_set_state(BT_MESH_LPN_ESTABLISHING);
return 0;
}
int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx,
struct os_mbuf *buf)
{
struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->om_data;
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
u16_t addr, counter;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Clear Confirm");
return -EINVAL;
}
if (lpn->state != BT_MESH_LPN_CLEAR) {
BT_WARN("Ignoring unexpected Friend Clear Confirm");
return 0;
}
addr = sys_be16_to_cpu(msg->lpn_addr);
counter = sys_be16_to_cpu(msg->lpn_counter);
BT_DBG("LPNAddress 0x%04x LPNCounter 0x%04x", addr, counter);
if (addr != bt_mesh_primary_addr() || counter != lpn->counter) {
BT_WARN("Invalid parameters in Friend Clear Confirm");
return 0;
}
clear_friendship(bt_mesh.lpn.disable);
return 0;
}
static void lpn_group_add(u16_t group)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
u16_t *free_slot = NULL;
int i;
for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) {
if (lpn->groups[i] == group) {
atomic_clear_bit(lpn->to_remove, i);
return;
}
if (!free_slot && lpn->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
free_slot = &lpn->groups[i];
}
}
if (!free_slot) {
BT_WARN("Friend Subscription List exceeded!");
return;
}
*free_slot = group;
lpn->groups_changed = 1;
}
static void lpn_group_del(u16_t group)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
int i;
for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) {
if (lpn->groups[i] == group) {
if (atomic_test_bit(lpn->added, i) ||
atomic_test_bit(lpn->pending, i)) {
atomic_set_bit(lpn->to_remove, i);
lpn->groups_changed = 1;
} else {
lpn->groups[i] = BT_MESH_ADDR_UNASSIGNED;
}
}
}
}
static inline int group_popcount(atomic_t *target)
{
#if CONFIG_BLUETOOTH_MESH_LPN_GROUPS > 32
int i, count = 0;
for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) {
count += popcount(atomic_get(&target[i]));
}
#else
return popcount(atomic_get(target));
#endif
}
static bool sub_update(u8_t op)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
int added_count = group_popcount(lpn->added);
struct bt_mesh_msg_ctx ctx = {
.net_idx = bt_mesh.sub[0].net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = lpn->frnd,
.send_ttl = 0,
.friend_cred = 1,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
};
struct bt_mesh_ctl_friend_sub req;
size_t i, g;
if (lpn->sent_req) {
return false;
}
for (i = 0, g = 0; i < ARRAY_SIZE(lpn->groups); i++) {
if (lpn->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
continue;
}
if (op == TRANS_CTL_OP_FRIEND_SUB_ADD) {
if (atomic_test_bit(lpn->added, i)) {
continue;
}
} else {
if (!atomic_test_bit(lpn->to_remove, i)) {
continue;
}
}
if (added_count + g >= lpn->queue_size) {
BT_WARN("Friend Queue Size exceeded");
break;
}
req.addr_list[g++] = sys_cpu_to_be16(lpn->groups[i]);
atomic_set_bit(lpn->pending, i);
if (g == ARRAY_SIZE(req.addr_list)) {
break;
}
}
if (g == 0) {
group_zero(lpn->pending);
return false;
}
req.xact = lpn->xact_next++;
if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2, req_sent) < 0) {
group_zero(lpn->pending);
return false;
}
lpn->xact_pending = req.xact;
lpn->sent_req = op;
return true;
}
static void lpn_timeout(struct os_event *work)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
#if (MYNEWT_VAL(BLE_MESH_DEBUG_LOW_POWER))
BT_DBG("state: %s", state2str(lpn->state));
#endif
switch (lpn->state) {
case BT_MESH_LPN_DISABLED:
break;
case BT_MESH_LPN_CLEAR:
clear_friendship(bt_mesh.lpn.disable);
break;
case BT_MESH_LPN_ENABLED:
send_friend_req();
break;
case BT_MESH_LPN_WAIT_OFFER:
BT_WARN("No acceptable Friend Offers received");
lpn->counter++;
lpn_set_state(BT_MESH_LPN_ENABLED);
k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT);
break;
case BT_MESH_LPN_ESTABLISHING:
BT_ERR("Timed out waiting for first Friend Update");
clear_friendship(false);
break;
case BT_MESH_LPN_ESTABLISHED:
if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) {
u8_t req = lpn->sent_req;
lpn->sent_req = 0;
if (!req || req == TRANS_CTL_OP_FRIEND_POLL) {
send_friend_poll();
} else {
sub_update(req);
}
break;
}
BT_ERR("No response from Friend after %u retries",
lpn->req_attempts);
clear_friendship(false);
break;
case BT_MESH_LPN_RECV_DELAY:
bt_mesh_scan_enable();
lpn_set_state(BT_MESH_LPN_WAIT_UPDATE);
k_delayed_work_submit(&lpn->timer,
lpn->recv_win + SCAN_LATENCY);
break;
case BT_MESH_LPN_WAIT_UPDATE:
BT_WARN("No response from Friend during ReceiveWindow");
bt_mesh_scan_disable();
lpn_set_state(BT_MESH_LPN_ESTABLISHED);
k_delayed_work_submit(&lpn->timer, POLL_RETRY_TIMEOUT);
break;
default:
__ASSERT(0, "Unhandled LPN state");
break;
}
}
void bt_mesh_lpn_group_add(u16_t group)
{
BT_DBG("group 0x%04x", group);
lpn_group_add(group);
if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) {
return;
}
sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
}
void bt_mesh_lpn_group_del(u16_t *groups, size_t group_count)
{
int i;
for (i = 0; i < group_count; i++) {
if (groups[i] != BT_MESH_ADDR_UNASSIGNED) {
BT_DBG("group 0x%04x", groups[i]);
lpn_group_del(groups[i]);
}
}
if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) {
return;
}
sub_update(TRANS_CTL_OP_FRIEND_SUB_REM);
}
static s32_t poll_timeout(struct bt_mesh_lpn *lpn)
{
/* If we're waiting for segment acks keep polling at high freq */
if (bt_mesh_tx_in_progress()) {
return min(POLL_TIMEOUT(lpn), K_SECONDS(1));
}
if (lpn->poll_timeout < POLL_TIMEOUT(lpn)) {
lpn->poll_timeout *= 2;
lpn->poll_timeout = min(lpn->poll_timeout, POLL_TIMEOUT(lpn));
}
BT_DBG("Poll Timeout is %ums", lpn->poll_timeout);
return lpn->poll_timeout;
}
int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx,
struct os_mbuf *buf)
{
struct bt_mesh_ctl_friend_sub_confirm *msg = (void *)buf->om_data;
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Subscription Confirm");
return -EINVAL;
}
BT_DBG("xact 0x%02x", msg->xact);
if (!lpn->sent_req) {
BT_WARN("No pending subscription list message");
return 0;
}
if (msg->xact != lpn->xact_pending) {
BT_WARN("Transaction mismatch (0x%02x != 0x%02x)",
msg->xact, lpn->xact_pending);
return 0;
}
if (lpn->sent_req == TRANS_CTL_OP_FRIEND_SUB_ADD) {
group_set(lpn->added, lpn->pending);
group_zero(lpn->pending);
} else if (lpn->sent_req == TRANS_CTL_OP_FRIEND_SUB_REM) {
int i;
group_clear(lpn->added, lpn->pending);
for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) {
if (atomic_test_and_clear_bit(lpn->pending, i) &&
atomic_test_and_clear_bit(lpn->to_remove, i)) {
lpn->groups[i] = BT_MESH_ADDR_UNASSIGNED;
}
}
} else {
BT_WARN("Unexpected Friend Subscription Confirm");
return 0;
}
friend_response_received(lpn);
if (lpn->groups_changed) {
sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
sub_update(TRANS_CTL_OP_FRIEND_SUB_REM);
if (!lpn->sent_req) {
lpn->groups_changed = 0;
}
}
if (lpn->pending_poll) {
send_friend_poll();
}
if (!lpn->sent_req) {
k_delayed_work_submit(&lpn->timer, poll_timeout(lpn));
}
return 0;
}
int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
struct os_mbuf *buf)
{
struct bt_mesh_ctl_friend_update *msg = (void *)buf->om_data;
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
struct bt_mesh_subnet *sub = rx->sub;
u32_t iv_index;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Update");
return -EINVAL;
}
if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) {
BT_WARN("Unexpected friend update");
return 0;
}
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !rx->new_key) {
BT_WARN("Ignoring Phase 2 KR Update secured using old key");
return 0;
}
if (bt_mesh.ivu_initiator &&
bt_mesh.iv_update == BT_MESH_IV_UPDATE(msg->flags)) {
bt_mesh_beacon_ivu_initiator(false);
}
if (lpn->state == BT_MESH_LPN_ESTABLISHING) {
/* This is normally checked on the transport layer, however
* in this state we're also still accepting master
* credentials so we need to ensure the right ones (Friend
* Credentials) were used for this message.
*/
if (!rx->ctx.friend_cred) {
BT_WARN("Friend Update with wrong credentials");
return -EINVAL;
}
BT_INFO("Friendship established with 0x%04x", lpn->frnd);
/* Set initial poll timeout */
lpn->poll_timeout = min(POLL_TIMEOUT(lpn), K_SECONDS(1));
}
friend_response_received(lpn);
iv_index = sys_be32_to_cpu(msg->iv_index);
BT_DBG("flags 0x%02x iv_index 0x%08x md %u", msg->flags, iv_index,
msg->md);
if (bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(msg->flags),
rx->new_key)) {
bt_mesh_net_beacon_update(sub);
}
bt_mesh_iv_update(iv_index, BT_MESH_IV_UPDATE(msg->flags));
if (lpn->groups_changed) {
sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
sub_update(TRANS_CTL_OP_FRIEND_SUB_REM);
if (!lpn->sent_req) {
lpn->groups_changed = 0;
}
}
if (msg->md) {
BT_DBG("Requesting for more messages");
send_friend_poll();
}
if (!lpn->sent_req) {
k_delayed_work_submit(&lpn->timer, poll_timeout(lpn));
}
return 0;
}
void bt_mesh_lpn_friend_poll(void)
{
BT_DBG("Requesting more messages");
send_friend_poll();
}
int bt_mesh_lpn_init(void)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
k_delayed_work_init(&lpn->timer, lpn_timeout);
if (lpn->state == BT_MESH_LPN_ENABLED) {
send_friend_req();
}
return 0;
}
#endif //MYNEWT_VAL(BLE_MESH_LOW_POWER) == 1
+59
View File
@@ -0,0 +1,59 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __LPN_H__
#define __LPN_H__
#include "mesh/mesh.h"
int
bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
int
bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
int
bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
int
bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
static inline bool
bt_mesh_lpn_established(void)
{
#if (MYNEWT_VAL(BLE_MESH_LOW_POWER))
return (bt_mesh.lpn.state >= BT_MESH_LPN_ESTABLISHED);
#else
return false;
#endif
}
static inline bool
bt_mesh_lpn_waiting_update(void)
{
#if (MYNEWT_VAL(BLE_MESH_LOW_POWER))
return (bt_mesh.lpn.state == BT_MESH_LPN_WAIT_UPDATE);
#else
return false;
#endif
}
void
bt_mesh_lpn_friend_poll(void);
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(void);
int
bt_mesh_lpn_init(void);
#endif
+202
View File
@@ -0,0 +1,202 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdbool.h>
#include <errno.h>
#include "syscfg/syscfg.h"
#include "os/os_mbuf.h"
#include "mesh/mesh.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG))
#include "host/ble_hs_log.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_priv.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;
BLE_HS_LOG(INFO, "Primary Element: 0x%04x", addr);
if ((MYNEWT_VAL(BLE_MESH_PB_GATT))) {
bt_mesh_proxy_prov_disable();
}
err = bt_mesh_net_create(net_idx, flags, net_key, iv_index);
if (err) {
if ((MYNEWT_VAL(BLE_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 ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))
&& bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED) {
bt_mesh_proxy_gatt_enable();
bt_mesh_adv_update();
}
/* If PB-ADV is disabled then scanning will have been disabled */
if (!(MYNEWT_VAL(BLE_MESH_PB_ADV))) {
bt_mesh_scan_enable();
}
if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
bt_mesh_lpn_init();
}
if ((MYNEWT_VAL(BLE_MESH_FRIEND))) {
bt_mesh_friend_init();
}
return 0;
}
void
bt_mesh_reset(void)
{
if (!provisioned) {
goto enable_beacon;
}
bt_mesh_comp_unprovision();
bt_mesh.iv_index = 0;
bt_mesh.seq = 0;
bt_mesh.iv_update = 0;
bt_mesh.valid = 0;
bt_mesh.last_update = 0;
bt_mesh.ivu_initiator = 0;
k_delayed_work_cancel(&bt_mesh.ivu_complete);
if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
bt_mesh_lpn_disable();
}
if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) {
bt_mesh_proxy_gatt_disable();
}
if ((MYNEWT_VAL(BLE_MESH_PB_GATT))) {
bt_mesh_proxy_prov_enable();
}
memset(bt_mesh.dev_key, 0, sizeof(bt_mesh.dev_key));
memset(bt_mesh.rpl, 0, sizeof(bt_mesh.rpl));
provisioned = false;
enable_beacon:
if ((MYNEWT_VAL(BLE_MESH_PB_ADV))) {
/* Make sure we're scanning for provisioning inviations */
bt_mesh_scan_enable();
/* Enable unprovisioned beacon sending */
bt_mesh_beacon_enable();
}
else {
bt_mesh_scan_disable();
bt_mesh_beacon_disable();
}
}
bool
bt_mesh_is_provisioned(void)
{
return provisioned;
}
static int
bt_mesh_gap_event(struct ble_gap_event *event, void *arg)
{
ble_adv_gap_mesh_cb(event, arg);
#if (MYNEWT_VAL(BLE_MESH_PROXY))
ble_mesh_proxy_gap_event(event, arg);
#endif
return 0;
}
int
bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov,
const struct bt_mesh_comp *comp)
{
int err;
err = bt_mesh_comp_register(comp);
if (err) {
return err;
}
if (MYNEWT_VAL(BLE_MESH_PROV)) {
bt_mesh_prov_init(prov);
}
#if (MYNEWT_VAL(BLE_MESH_PROXY))
bt_mesh_proxy_init();
/* Need this to proper link.rx.buf allocation */
bt_mesh_prov_reset_link();
#endif
bt_mesh_net_init();
bt_mesh_trans_init();
bt_mesh_beacon_init();
bt_mesh_adv_init(own_addr_type);
#if (MYNEWT_VAL(BLE_MESH_PB_ADV))
/* Make sure we're scanning for provisioning inviations */
bt_mesh_scan_enable();
/* Enable unprovisioned beacon sending */
bt_mesh_beacon_enable();
#endif
#if (MYNEWT_VAL(BLE_MESH_PB_GATT))
bt_mesh_proxy_prov_enable();
#endif
ble_gap_mesh_cb_register(bt_mesh_gap_event, NULL);
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __MESH_PRIV_H
#define __MESH_PRIV_H
#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)
bool
bt_mesh_is_provisioned(void);
#endif
File diff suppressed because it is too large Load Diff
+308
View File
@@ -0,0 +1,308 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __NET_H__
#define __NET_H__
#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)
#include <stdbool.h>
#include "mesh/mesh.h"
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];
};
/* Friendship Credentials */
struct bt_mesh_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];
};
struct bt_mesh_subnet
{
s64_t beacon_sent; /* Time stamp 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.
*/
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 */
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 (MYNEWT_VAL(BLE_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;
};
struct bt_mesh_friend
{
u16_t lpn;
u8_t recv_delay;
u8_t fsn :1, send_last :1, send_offer :1, send_update :1;
s32_t poll_to;
u16_t lpn_counter;
u16_t counter;
s8_t rssi;
struct k_delayed_work timer;
struct os_mbuf *last;
/* TU BYLO KFIFO*/
struct os_eventq queue;
};
#if (MYNEWT_VAL(BLE_MESH_LOW_POWER))
#define LPN_GROUPS MYNEWT_VAL(BLE_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_ENABLED, /* LPN enabled, but no Friend */
BT_MESH_LPN_WAIT_OFFER, /* Friend Req sent */
BT_MESH_LPN_ESTABLISHING, /* First Friend Poll 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 */
/* Friend Queue Size */
u8_t queue_size;
/* LPNCounter */
u16_t counter;
/* 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 */
pending_update :1, /* Update blocked by SDU in progress */
valid :1; /* 0 if unused */
s64_t last_update; /* Time since last IV Update change */
#if MYNEWT_VAL(BLE_MESH_LOCAL_INTERFACE)
/* Local network interface */
struct os_callout local_work;
struct os_eventq local_queue;
struct os_event local_ev;
#endif
#if MYNEWT_VAL(BLE_MESH_FRIEND)
struct bt_mesh_friend frnd; /* Friend state */
#endif
#if (MYNEWT_VAL(BLE_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[MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)];
struct bt_mesh_subnet sub[MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)];
struct bt_mesh_rpl rpl[MYNEWT_VAL(BLE_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;
u64_t hash; /* Hash for the relay cache */
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 */
ctl :1, /* Network Control */
net_if :2; /* Network interface */
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;
};
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)
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);
int
bt_mesh_friend_cred_set(struct bt_mesh_friend_cred *cred, u8_t idx,
const u8_t net_key[16]);
void
bt_mesh_friend_cred_refresh(u16_t net_idx);
int
bt_mesh_friend_cred_update(u16_t net_idx, u8_t idx, const u8_t net_key[16]);
struct bt_mesh_friend_cred *
bt_mesh_friend_cred_add(u16_t net_idx, const u8_t net_key[16], u8_t idx,
u16_t addr, u16_t lpn_counter, u16_t frnd_counter);
void
bt_mesh_friend_cred_clear(struct bt_mesh_friend_cred *cred);
int
bt_mesh_friend_cred_del(u16_t net_idx, u16_t addr);
bool
bt_mesh_kr_update(struct bt_mesh_subnet *sub, u8_t new_kr, bool new_key);
int
bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub);
void
bt_mesh_rpl_reset(void);
void
bt_mesh_iv_update(u32_t iv_index, bool iv_update);
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 os_mbuf *buf,
bool proxy);
int
bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
bt_mesh_adv_func_t cb);
int
bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct os_mbuf *buf,
bool new_key,
bool friend_cred, bt_mesh_adv_func_t cb);
int
bt_mesh_net_decode(struct os_mbuf *data, enum bt_mesh_net_if net_if,
struct bt_mesh_net_rx *rx, struct os_mbuf *buf,
struct net_buf_simple_state *state);
void
bt_mesh_net_recv(struct os_mbuf *data, s8_t rssi, enum bt_mesh_net_if net_if);
void
bt_mesh_net_init(void);
#endif
File diff suppressed because it is too large Load Diff
+38
View File
@@ -0,0 +1,38 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __PROV_H__
#define __PROV_H__
#include "os/os_mbuf.h"
#include "mesh/mesh.h"
#include "../src/ble_hs_conn_priv.h"
void
bt_mesh_pb_adv_recv(struct os_mbuf *buf);
bool
bt_prov_active(void);
int
bt_mesh_pb_gatt_open(uint16_t conn_handle);
int
bt_mesh_pb_gatt_close(uint16_t conn_handle);
int
bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf);
const u8_t *
bt_mesh_prov_get_uuid(void);
void
bt_mesh_prov_init(const struct bt_mesh_prov *prov);
void
bt_mesh_prov_reset_link(void);
#endif
File diff suppressed because it is too large Load Diff
+41
View File
@@ -0,0 +1,41 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef __PROXY_H__
#define __PROXY_H__
#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
#include "mesh/mesh.h"
int bt_mesh_proxy_send(uint16_t conn_handle, u8_t type, struct os_mbuf *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_beacon_send(struct bt_mesh_subnet *sub);
struct os_mbuf * bt_mesh_proxy_get_buf(void);
s32_t bt_mesh_proxy_adv_start(void);
void bt_mesh_proxy_adv_stop(void);
bool bt_mesh_proxy_relay(struct os_mbuf *buf, u16_t dst);
void bt_mesh_proxy_addr_add(struct os_mbuf *buf, u16_t addr);
int bt_mesh_proxy_init(void);
int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg);
#endif
File diff suppressed because it is too large Load Diff
+102
View File
@@ -0,0 +1,102 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#include "mesh/mesh.h"
#define BT_MESH_TX_SEG_COUNT (MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT) - 3)
#define BT_MESH_TX_SDU_MAX (BT_MESH_TX_SEG_COUNT * 12)
#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;
}__attribute__((__packed__));
struct bt_mesh_ctl_friend_update
{
u8_t flags;
u32_t iv_index;
u8_t md;
}__attribute__((__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;
}__attribute__((__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;
}__attribute__((__packed__));
struct bt_mesh_ctl_friend_clear
{
u16_t lpn_addr;
u16_t lpn_counter;
}__attribute__((__packed__));
struct bt_mesh_ctl_friend_clear_confirm
{
u16_t lpn_addr;
u16_t lpn_counter;
}__attribute__((__packed__));
struct bt_mesh_ctl_friend_sub
{
u8_t xact;
u16_t addr_list[5];
}__attribute__((__packed__));
struct bt_mesh_ctl_friend_sub_confirm
{
u8_t xact;
}__attribute__((__packed__));
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);
int
bt_mesh_ctl_send(struct bt_mesh_net_tx *tx, u8_t ctl_op, void *data,
size_t data_len, bt_mesh_adv_func_t cb);
int
bt_mesh_trans_send(struct bt_mesh_net_tx *tx, struct os_mbuf *msg,
bt_mesh_cb_t cb, void *cb_data);
int
bt_mesh_trans_recv(struct os_mbuf *buf, struct bt_mesh_net_rx *rx);
void
bt_mesh_trans_init(void);
+322
View File
@@ -0,0 +1,322 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
# Package: net/nimble/host/mesh
syscfg.defs:
BLE_MESH_PROV:
description: >
Enable provisioning. It is automatically enabled whenever
BLE_MESH_PB_ADV or BLE_MESH_PB_GATT is set.
value: 1
BLE_MESH_PB_ADV:
description: >
Enable this option to allow the device to be provisioned over
the advertising bearer.
value: 1
BLE_MESH_PROXY:
description: >
Enable proxy. This is automatically set whenever BLE_MESH_PB_GATT or
BLE_MESH_GATT_PROXY is set.
value: 0
BLE_MESH_PB_GATT:
description: >
Enable this option to allow the device to be provisioned over
the advertising bearer.
value: 1
BLE_MESH_GATT_PROXY:
descruption: >
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.
value: 1
BLE_MESH_PROXY_FILTER_SIZE:
descryption: >
This option specifies how many Proxy Filter entries the local
node supports.
value: 1
BLE_MESH_LOCAL_INTERFACE:
description: >
This is needed in order to send messages between two local Mesh
elements. Only disable it if you're sure this will not be needed
(which description: >s save a little bit of memory).
value: 1
BLE_MESH_SUBNET_COUNT:
description: >
This option specifies how many subnets a Mesh network can
participate in at the same time.
value: 1
BLE_MESH_APP_KEY_COUNT:
description: >
This option specifies how many application keys the device can
store per network.
value: 1
BLE_MESH_MODEL_KEY_COUNT:
description: >
This option specifies how many application keys each model can
at most be bound to.
value: 1
BLE_MESH_MODEL_GROUP_COUNT:
description: >
This option specifies how many group addresses each model can
at most be subscribed to.
value: 1
BLE_MESH_LABEL_COUNT:
description: >
This option specifies how many Label UUIDs can be stored.
value: 1
BLE_MESH_CRPL:
description: >
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.
value: 10
BLE_MESH_ADV_TASK_PRIO:
description: >
Advertising task prio (FIXME)
value: 9
BLE_MESH_MSG_CACHE_SIZE:
description: >
Number of messages that are cached for the network. This description
prevent unnecessary decryption operations and unnecessary
relays. This option is similar to the replay protection list,
but has a different purpose.
value: 10
BLE_MESH_ADV_BUF_COUNT:
description: >
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.
value: 10
BLE_MESH_TX_SEG_MSG_COUNT:
description: >
Maximum number of simultaneous outgoing multi-segment and/or
reliable messages.
value: 4
BLE_MESH_RX_SEG_MSG_COUNT:
description: >
Maximum number of simultaneous incoming multi-segment and/or
reliable messages.
value: 2
BLE_MESH_RX_SDU_MAX:
description: >
Maximum incoming Upper Transport Access PDU length. Leave this
to the value; value, unless you really need to optimize memory
usage.
value: 384
BLE_MESH_RELAY:
description: >
Support for acting as a Mesh Relay Node.
value: 0
BLE_MESH_LOW_POWER:
description: >
Enable this option to be able to act as a Low Power Node.
value: 1
BLE_MESH_LPN_RSSI_FACTOR:
description: >
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.
value: 0
BLE_MESH_LPN_RECV_WIN_FACTOR:
description: >
The contribution of the supported Receive Window used in
Friend Offer Delay calculations. 0 = 1, 1 = 1.5, 2 = 2, 3 = 2.5.
value: 0
BLE_MESH_LPN_MIN_QUEUE_SIZE:
description: >
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.
value: 1
BLE_MESH_LPN_RECV_DELAY:
description: >
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.
value: 20
BLE_MESH_LPN_POLL_TIMEOUT:
description: >
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.
value: 100
BLE_MESH_LPN_SCAN_LATENCY:
description: >
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.
value: 10
BLE_MESH_LPN_GROUPS:
description: >
Maximum number of groups that the LPN can subscribe to.
value: 10
BLE_MESH_FRIEND:
description: >
Enable this option to be able to act as a Friend Node.
value: 1
BLE_MESH_FRIEND_RECV_WIN:
description: >
Receive Window in milliseconds supported by the Friend node.
value: 255
BLE_MESH_FRIEND_QUEUE_SIZE:
description: >
Queue Size available on the Friend node.
value: 16
BLE_MESH_FRIEND_SUB_LIST_SIZE:
description: >
Size of the Subscription List that can be supported by a
Friend node for a Low Power node.
value: 16
BLE_MESH_FRIEND_LPN_COUNT:
description: >
Number of Low Power Nodes the Friend can have a Friendship
with simultaneously.
value: 1
BLE_MESH_DEBUG:
description: >
Use this option to enable debug logs for the Bluetooth
Mesh functionality.
value: 0
BLE_MESH_DEBUG_NET:
description: >
Use this option to enable Network layer debug logs for the
Bluetooth Mesh functionality.
value: 0
BLE_MESH_DEBUG_TRANS:
description: >
Use this option to enable Transport layer debug logs for the
Bluetooth Mesh functionality.
value: 0
BLE_MESH_DEBUG_BEACON:
description: >
Use this option to enable Beacon-related debug logs for the
Bluetooth Mesh functionality.
value: 0
BLE_MESH_DEBUG_CRYPTO:
description: >
Use this option to enable cryptographic debug logs for the
Bluetooth Mesh functionality.
value: 0
BLE_MESH_DEBUG_PROV:
description: >
Use this option to enable Provisioning debug logs for the
Bluetooth Mesh functionality.
value: 0
BLE_MESH_DEBUG_ACCESS:
description: >
Use this option to enable Access layer and device composition
related debug logs for Bluetooth Mesh.
value: 0
BLE_MESH_DEBUG_MODEL:
description: >
Use this option to enable debug logs for the Foundation
Models.
value: 0
BLE_MESH_DEBUG_ADV:
description: >
Use this option to enable advertising debug logs for
the Bluetooth Mesh functionality.
value: 0
BLE_MESH_DEBUG_LOW_POWER:
description: >
Use this option to enable Low Power debug logs for the
Bluetooth Mesh functionality.
value: 0
BLE_MESH_DEBUG_FRIEND:
description: >
Use this option to enable Friend debug logs for the
Bluetooth Mesh functionality.
value: 0
BLE_MESH_DEBUG_PROXY:
description: >
Use this option to enable Proxy protocol debug logs.
value: 0
BLE_MESH_IV_UPDATE_TEST:
description: >
This option removes the 96 hour limit of the IV Update
Procedure and lets the state be changed at any time.
value: 0
BLE_MESH_DEV_UUID:
description: >
Device UUID
value: ((uint8_t[16]){0x11, 0x22, 0})
syscfg.vals.BLE_MESH_GATT_PROXY:
BLE_MESH_PROXY: 1
syscfg.vals.BLE_MESH_PB_GATT:
BLE_MESH_PROXY: 1
BLE_MESH_PROV: 1
syscfg.vals.BLE_MESH_PB_ADV:
BLE_MESH_PROV: 1
+3
View File
@@ -39,6 +39,9 @@ pkg.deps.BLE_SM_SC:
pkg.deps.BLE_MONITOR_RTT:
- hw/drivers/rtt
pkg.deps.BLE_MESH:
- net/nimble/host/mesh
pkg.req_apis:
- ble_transport
- console
+78 -19
View File
@@ -113,9 +113,19 @@ struct ble_gap_master_state {
uint8_t extended:1;
} disc;
};
};
static bssnz_t struct ble_gap_master_state ble_gap_master;
#if MYNEWT_VAL(BLE_MESH)
struct ble_gap_mesh_state {
ble_gap_event_fn *cb;
void *cb_arg;
} ble_gap_mesh;
#endif
/**
* The state of the in-progress slave connection. If no slave connection is
* currently in progress, then the op field is set to BLE_GAP_OP_NULL.
@@ -521,6 +531,17 @@ ble_gap_set_prefered_le_phy(uint16_t conn_handle, uint8_t tx_phys_mask,
buf, sizeof(buf), NULL, 0, NULL);
}
#if MYNEWT_VAL(BLE_MESH)
int
ble_gap_mesh_cb_register(ble_gap_event_fn *cb, void *cb_arg)
{
ble_gap_mesh.cb = cb;
ble_gap_mesh.cb_arg = cb_arg;
return 0;
}
#endif
/*****************************************************************************
* $misc *
*****************************************************************************/
@@ -587,6 +608,16 @@ ble_gap_slave_reset_state(void)
ble_hs_timer_resched();
}
static bool
ble_gap_has_client(struct ble_gap_master_state *out_state)
{
if (!out_state) {
return 0;
}
return out_state->cb;
}
static void
ble_gap_master_extract_state(struct ble_gap_master_state *out_state,
int reset_state)
@@ -638,7 +669,7 @@ ble_gap_master_connect_failure(int status)
int rc;
ble_gap_master_extract_state(&state, 1);
if (state.cb != NULL) {
if (!ble_gap_has_client(&state)) {
memset(&event, 0, sizeof event);
event.type = BLE_GAP_EVENT_CONNECT;
event.connect.status = status;
@@ -686,27 +717,32 @@ ble_gap_is_extended_disc(void)
static void
ble_gap_disc_report(void *desc)
{
struct ble_gap_master_state state;
struct ble_gap_master_state state;;
struct ble_gap_event event;
ble_gap_master_extract_state(&state, 0);
if (state.cb != NULL) {
memset(&event, 0, sizeof event);
if (ble_gap_is_extended_disc()) {
memset(&event, 0, sizeof event);
if (ble_gap_is_extended_disc()) {
#if MYNEWT_VAL(BLE_EXT_ADV)
event.type = BLE_GAP_EVENT_EXT_DISC;
event.ext_disc = *((struct ble_gap_ext_disc_desc *)desc);
event.type = BLE_GAP_EVENT_EXT_DISC;
event.ext_disc = *((struct ble_gap_ext_disc_desc *)desc);
#else
assert(0);
assert(0);
#endif
} else {
event.type = BLE_GAP_EVENT_DISC;
event.disc = *((struct ble_gap_disc_desc *)desc);
}
} else {
event.type = BLE_GAP_EVENT_DISC;
event.disc = *((struct ble_gap_disc_desc *)desc);
}
ble_gap_master_extract_state(&state, 0);
if (ble_gap_has_client(&state)) {
state.cb(&event, state.cb_arg);
}
#if MYNEWT_VAL(BLE_MESH)
if (ble_gap_mesh.cb) {
ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
}
#endif
}
static void
@@ -715,14 +751,19 @@ ble_gap_disc_complete(void)
struct ble_gap_master_state state;
struct ble_gap_event event;
memset(&event, 0, sizeof event);
event.type = BLE_GAP_EVENT_DISC_COMPLETE;
ble_gap_master_extract_state(&state, 1);
if (state.cb != NULL) {
memset(&event, 0, sizeof event);
event.type = BLE_GAP_EVENT_DISC_COMPLETE;
if (ble_gap_has_client(&state)) {
ble_gap_call_event_cb(&event, state.cb, state.cb_arg);
}
#if MYNEWT_VAL(BLE_MESH)
if (ble_gap_mesh.cb) {
ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
}
#endif
}
static void
@@ -924,6 +965,12 @@ ble_gap_conn_broken(uint16_t conn_handle, int reason)
event.disconnect.reason = reason;
ble_gap_call_event_cb(&event, snap.cb, snap.cb_arg);
#if MYNEWT_VAL(BLE_MESH)
if (ble_gap_mesh.cb) {
ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
}
#endif
STATS_INC(ble_gap_stats, disconnect);
}
@@ -1341,6 +1388,12 @@ ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt)
event.connect.status = 0;
ble_gap_call_conn_event_cb(&event, evt->connection_handle);
#if MYNEWT_VAL(BLE_MESH)
if (ble_gap_mesh.cb) {
ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
}
#endif
ble_gap_rd_rem_sup_feat_tx(evt->connection_handle);
return 0;
@@ -4138,6 +4191,12 @@ ble_gap_subscribe_event(uint16_t conn_handle, uint16_t attr_handle,
event.subscribe.prev_indicate = !!prev_indicate;
event.subscribe.cur_indicate = !!cur_indicate;
ble_gap_call_conn_event_cb(&event, conn_handle);
#if MYNEWT_VAL(BLE_MESH)
if (ble_gap_mesh.cb) {
ble_gap_mesh.cb(&event, ble_gap_mesh.cb_arg);
}
#endif
}
/*****************************************************************************
+8
View File
@@ -353,3 +353,11 @@ syscfg.defs:
mechanism.
value: 8
BLE_MESH:
description: >
Enable Bluetooth Mesh
value: 0
syscfg.vals.BLE_MESH:
BLE_SM_SC: 1