mirror of
https://github.com/espressif/esp-nimble.git
synced 2026-10-08 15:47:22 +00:00
Merge pull request #511 from rymanluk/porting
nimble: Port Bluetooth Mesh from Zephyr to Mynewt X-Original-Commit: afe2a6a94aa65323684a54f1eff85ee63d8ddde3
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__ */
|
||||
@@ -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
|
||||
@@ -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 */
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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(¶m, &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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user