update NimBLE lib

This commit is contained in:
technyon
2022-06-12 10:55:16 +02:00
parent 6557bd8c72
commit c5ca2da941
178 changed files with 19582 additions and 8440 deletions

View File

@@ -703,13 +703,29 @@ std::vector<NimBLERemoteService*>* NimBLEClient::getServices(bool refresh) {
/**
* @brief Retrieves the full database of attributes that the peripheral has available.
* @return True if successful.
*/
void NimBLEClient::discoverAttributes() {
for(auto svc: *getServices(true)) {
for(auto chr: *svc->getCharacteristics(true)) {
chr->getDescriptors(true);
bool NimBLEClient::discoverAttributes() {
deleteServices();
if (!retrieveServices()){
return false;
}
for(auto svc: m_servicesVector) {
if (!svc->retrieveCharacteristics()) {
return false;
}
for(auto chr: svc->m_characteristicVector) {
if (!chr->retrieveDescriptors()) {
return false;
}
}
}
return true;
} // discoverAttributes

View File

@@ -70,7 +70,7 @@ public:
void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
uint16_t latency, uint16_t timeout);
void setDataLen(uint16_t tx_octets);
void discoverAttributes();
bool discoverAttributes();
NimBLEConnInfo getConnInfo();
int getLastError();
#if CONFIG_BT_NIMBLE_EXT_ADV

View File

@@ -616,6 +616,7 @@ bool NimBLERemoteCharacteristic::setNotify(uint16_t val, notify_callback notifyC
NIMBLE_LOGD(LOG_TAG, "<< setNotify()");
response = true; // Always write with response as per Bluetooth core specification.
return desc->writeValue((uint8_t *)&val, 2, response);
} // setNotify

View File

@@ -73,8 +73,8 @@ public:
bool subscribe(bool notifications = true,
notify_callback notifyCallback = nullptr,
bool response = false);
bool unsubscribe(bool response = false);
bool response = true);
bool unsubscribe(bool response = true);
bool registerForNotify(notify_callback notifyCallback,
bool notifications = true,
bool response = true)

View File

@@ -34,7 +34,7 @@ NimBLEScan::NimBLEScan() {
m_scan_params.itvl = 0; // This is defined as the time interval from when the Controller started its last LE scan until it begins the subsequent LE scan. (units=0.625 msec)
m_scan_params.window = 0; // The duration of the LE scan. LE_Scan_Window shall be less than or equal to LE_Scan_Interval (units=0.625 msec)
m_scan_params.limited = 0; // If set, only discover devices in limited discoverable mode.
m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device.
m_scan_params.filter_duplicates = 1; // If set, the controller ignores all but the first advertisement from each device.
m_pAdvertisedDeviceCallbacks = nullptr;
m_ignoreResults = false;
m_pTaskData = nullptr;
@@ -134,6 +134,10 @@ NimBLEScan::~NimBLEScan() {
event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP));
if (pScan->m_pAdvertisedDeviceCallbacks) {
if (pScan->m_scan_params.filter_duplicates && advertisedDevice->m_callbackSent) {
return 0;
}
// If not active scanning or scan response is not available
// or extended advertisement scanning, report the result to the callback now.
if(pScan->m_scan_params.passive || !isLegacyAdv ||

View File

@@ -33,6 +33,7 @@ Features highlight:
- Support for up to 32 simultaneous connections.
- Legacy and SC (secure connections) SMP support (pairing and bonding).
- Advertising Extensions.
- Periodic Advertising.
- Coded (aka Long Range) and 2M PHYs.
- Bluetooth Mesh.

View File

@@ -1,6 +1,6 @@
# RELEASE NOTES
18 March 2020 - Apache NimBLE v1.3.0
24 March 2021 - Apache NimBLE v1.4.0
For full release notes, please visit the
[Apache Mynewt Wiki](https://cwiki.apache.org/confluence/display/MYNEWT/Release+Notes).
@@ -10,23 +10,12 @@ replaces the proprietary SoftDevice on Nordic chipsets.
New features in this version of NimBLE include:
* Support for Bluetooth Core Specification 5.1
* New blestress test application
* Dialog DA1469x CMAC driver
* Support for LE Secure Connections out-of-band (OOB) association model
* Support for automated generation of syscfg for ports
* Qualification related bugfixes
* BLE Mesh improvements - fixes and resync with latest Zephyr code
* RIOT OS port fixes and improvements
* btshell sample application improvements
* improvements for bttester application
* Controller duplicates filtering improvements
* Multi PHY support improvements
* Memory and CPU usage optimizations
* Use of packed structs for HCI (code size reduction)
* Linux sample improvements
* PTS test instructions updates
* Clock managements improvements in controller
* Support for PHY on Dialog Configurable MAC (CMAC)
* Support for PHY on Nordic nRF5340
* Support for Apache NuttX port of NimBLE
* Controller-to-host flow control support
* Support for USB transport
* Various bugfixes
If working on next-generation RTOS and Bluetooth protocol stack
sounds exciting to you, get in touch, by sending a mail to the Apache Mynewt

View File

@@ -7,7 +7,7 @@
extern "C" {
#endif
#define console_printf printf
#define console_printf(_fmt, ...) printf(_fmt, ##__VA_ARGS__)
#ifdef __cplusplus
}

View File

@@ -922,6 +922,10 @@
#define MYNEWT_VAL_BLE_MESH_LPN_GROUPS (10)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR
#define MYNEWT_VAL_BLE_MESH_LPN_SUB_ALL_NODES_ADDR (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT
#define MYNEWT_VAL_BLE_MESH_LPN_INIT_POLL_TIMEOUT (MYNEWT_VAL_BLE_MESH_LPN_POLL_TIMEOUT)
#endif
@@ -1043,6 +1047,10 @@
#endif
#endif
#ifndef MYNEWT_VAL_BLE_MESH_CDB
#define MYNEWT_VAL_BLE_MESH_CDB (0)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL (1)
#endif
@@ -1088,6 +1096,14 @@
#define MYNEWT_VAL_BLE_MESH_RX_SDU_MAX (72)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_SEG_BUFS
#define MYNEWT_VAL_BLE_MESH_SEG_BUFS (72)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MAX
#define MYNEWT_VAL_BLE_MESH_RX_SEG_MAX (3)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT
#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (2)
#endif
@@ -1100,6 +1116,63 @@
#define MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE (128)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT
#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_COUNT (4)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST
#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_UNICAST (400)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP
#define MYNEWT_VAL_BLE_MESH_TX_SEG_RETRANS_TIMEOUT_GROUP (50)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS
#define MYNEWT_VAL_BLE_MESH_LOOPBACK_BUFS (3)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_DEFAULT_TTL
#define MYNEWT_VAL_BLE_MESH_DEFAULT_TTL (7)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT
#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_COUNT (2)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL
#define MYNEWT_VAL_BLE_MESH_NETWORK_TRANSMIT_INTERVAL (20)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT
#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_COUNT (2)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT
#define MYNEWT_VAL_BLE_MESH_PB_ADV_RETRANS_TIMEOUT (500)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_RELAY_ENABLED
#define MYNEWT_VAL_BLE_MESH_RELAY_ENABLED (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED
#define MYNEWT_VAL_BLE_MESH_GATT_PROXY_ENABLED (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED
#define MYNEWT_VAL_BLE_MESH_FRIEND_ENABLED (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_BEACON_ENABLED
#define MYNEWT_VAL_BLE_MESH_BEACON_ENABLED (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL
#define MYNEWT_VAL_BLE_MESH_RELAY_RETRANSMIT_INTERVAL (20)
#endif
/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */
#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS
#define MYNEWT_VAL_BLE_MESH_SETTINGS (0)
@@ -1158,6 +1231,10 @@
#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (4)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT
#define MYNEWT_VAL_BLE_MESH_UNPROV_BEACON_INT (5)
#endif
/*** @apache-mynewt-nimble/nimble/host/services/ans */
#ifndef MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT
#define MYNEWT_VAL_BLE_SVC_ANS_NEW_ALERT_CAT (0)
@@ -1370,6 +1447,18 @@
#define MYNEWT_VAL_BLE_HCI_UART_STOP_BITS (1)
#endif
#ifndef CONFIG_BLE_TX_CCA_ENABLED
#define MYNEWT_VAL_BLE_TX_CCA_ENABLED (0)
#else
#define MYNEWT_VAL_BLE_TX_CCA_ENABLED (CONFIG_BLE_TX_CCA_ENABLED)
#endif
#ifndef CONFIG_BLE_CCA_RSSI_THRESH
#define MYNEWT_VAL_BLE_CCA_RSSI_THRESH (50)
#else
#define MYNEWT_VAL_BLE_CCA_RSSI_THRESH (CONFIG_BLE_CCA_RSSI_THRESH)
#endif
#ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG
#define MYNEWT_VAL_NEWT_FEATURE_LOGCFG (1)
#endif

View File

@@ -69,6 +69,29 @@ extern "C" {
/* Timing jitter as per spec is +/16 usecs */
#define BLE_LL_JITTER_USECS (16)
#if MYNEWT_VAL(BLE_LL_SCA) < 0
#error Invalid SCA value
#elif MYNEWT_VAL(BLE_LL_SCA) <= 20
#define BLE_LL_SCA_ENUM 7
#elif MYNEWT_VAL(BLE_LL_SCA) <= 30
#define BLE_LL_SCA_ENUM 6
#elif MYNEWT_VAL(BLE_LL_SCA) <= 50
#define BLE_LL_SCA_ENUM 5
#elif MYNEWT_VAL(BLE_LL_SCA) <= 75
#define BLE_LL_SCA_ENUM 4
#elif MYNEWT_VAL(BLE_LL_SCA) <= 100
#define BLE_LL_SCA_ENUM 3
#elif MYNEWT_VAL(BLE_LL_SCA) <= 150
#define BLE_LL_SCA_ENUM 2
#elif MYNEWT_VAL(BLE_LL_SCA) <= 250
#define BLE_LL_SCA_ENUM 1
#elif MYNEWT_VAL(BLE_LL_SCA) <= 500
#define BLE_LL_SCA_ENUM 0
#else
#error Invalid SCA value
#endif
/* Packet queue header definition */
STAILQ_HEAD(ble_ll_pkt_q, os_mbuf_pkthdr);
@@ -373,6 +396,12 @@ struct ble_dev_addr
#define BLE_LL_LLID_DATA_START (2)
#define BLE_LL_LLID_CTRL (3)
#define BLE_LL_LLID_IS_CTRL(hdr) \
(((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL)
#define BLE_LL_LLID_IS_DATA(hdr) \
((((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_DATA_START) || \
(((hdr) & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_DATA_FRAG))
/*
* CONNECT_REQ
* -> InitA (6 bytes)
@@ -415,6 +444,14 @@ struct ble_dev_addr
#define BLE_LL_ADDR_SUBTYPE_RPA (1)
#define BLE_LL_ADDR_SUBTYPE_NRPA (2)
/* ACAD data types */
#define BLE_LL_ACAD_CHANNEL_MAP_UPDATE_IND 0x28
struct ble_ll_acad_channel_map_update_ind {
uint8_t map[5];
uint16_t instant;
} __attribute__((packed));
/*--- External API ---*/
/* Initialize the Link Layer */
void ble_ll_init(void);
@@ -545,6 +582,7 @@ void ble_ll_rand_sample(uint8_t rnum);
int ble_ll_rand_data_get(uint8_t *buf, uint8_t len);
void ble_ll_rand_prand_get(uint8_t *prand);
int ble_ll_rand_start(void);
uint32_t ble_ll_rand(void);
static inline int
ble_ll_get_addr_type(uint8_t txrxflag)

View File

@@ -58,6 +58,8 @@ extern "C" {
/* Definition for RSSI when the RSSI is unknown */
#define BLE_LL_CONN_UNKNOWN_RSSI (127)
#define BLE_LL_CONN_HANDLE_ISO_OFFSET (0x0100)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/*
* Encryption states for a connection
@@ -69,6 +71,7 @@ extern "C" {
enum conn_enc_state {
CONN_ENC_S_UNENCRYPTED = 1,
CONN_ENC_S_ENCRYPTED,
CONN_ENC_S_ENC_RSP_TO_BE_SENT,
CONN_ENC_S_ENC_RSP_WAIT,
CONN_ENC_S_PAUSE_ENC_RSP_WAIT,
CONN_ENC_S_PAUSED,
@@ -270,6 +273,10 @@ struct ble_ll_conn_sm
uint8_t last_rxd_hdr_byte; /* note: possibly can make 1 bit since we
only use the MD bit now */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
uint16_t cth_flow_pending;
#endif
/* connection event mgmt */
uint8_t reject_reason;
uint8_t host_reply_opcode;

View File

@@ -39,7 +39,9 @@ extern "C" {
#define BLE_LL_CTRL_PROC_LE_PING (7)
#define BLE_LL_CTRL_PROC_DATA_LEN_UPD (8)
#define BLE_LL_CTRL_PROC_PHY_UPDATE (9)
#define BLE_LL_CTRL_PROC_NUM (10)
#define BLE_LL_CTRL_PROC_SCA_UPDATE (10)
#define BLE_LL_CTRL_PROC_CIS_CREATE (11)
#define BLE_LL_CTRL_PROC_NUM (12)
#define BLE_LL_CTRL_PROC_IDLE (255)
/* Checks if a particular control procedure is running */
@@ -54,45 +56,51 @@ extern "C" {
* -> Opcode (1 byte)
* -> Data (0 - 26 bytes)
*/
#define BLE_LL_CTRL_CONN_UPDATE_IND (0)
#define BLE_LL_CTRL_CHANNEL_MAP_REQ (1)
#define BLE_LL_CTRL_TERMINATE_IND (2)
#define BLE_LL_CTRL_ENC_REQ (3)
#define BLE_LL_CTRL_ENC_RSP (4)
#define BLE_LL_CTRL_START_ENC_REQ (5)
#define BLE_LL_CTRL_START_ENC_RSP (6)
#define BLE_LL_CTRL_UNKNOWN_RSP (7)
#define BLE_LL_CTRL_FEATURE_REQ (8)
#define BLE_LL_CTRL_FEATURE_RSP (9)
#define BLE_LL_CTRL_PAUSE_ENC_REQ (10)
#define BLE_LL_CTRL_PAUSE_ENC_RSP (11)
#define BLE_LL_CTRL_VERSION_IND (12)
#define BLE_LL_CTRL_REJECT_IND (13)
#define BLE_LL_CTRL_SLAVE_FEATURE_REQ (14)
#define BLE_LL_CTRL_CONN_PARM_REQ (15)
#define BLE_LL_CTRL_CONN_PARM_RSP (16)
#define BLE_LL_CTRL_REJECT_IND_EXT (17)
#define BLE_LL_CTRL_PING_REQ (18)
#define BLE_LL_CTRL_PING_RSP (19)
#define BLE_LL_CTRL_LENGTH_REQ (20)
#define BLE_LL_CTRL_LENGTH_RSP (21)
#define BLE_LL_CTRL_PHY_REQ (22)
#define BLE_LL_CTRL_PHY_RSP (23)
#define BLE_LL_CTRL_PHY_UPDATE_IND (24)
#define BLE_LL_CTRL_MIN_USED_CHAN_IND (25)
#define BLE_LL_CTRL_CTE_REQ (26)
#define BLE_LL_CTRL_CTE_RSP (27)
#define BLE_LL_CTRL_PERIODIC_SYNC_IND (28)
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ (29)
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP (30)
#define BLE_LL_CTRL_CONN_UPDATE_IND (0x00)
#define BLE_LL_CTRL_CHANNEL_MAP_REQ (0x01)
#define BLE_LL_CTRL_TERMINATE_IND (0x02)
#define BLE_LL_CTRL_ENC_REQ (0x03)
#define BLE_LL_CTRL_ENC_RSP (0x04)
#define BLE_LL_CTRL_START_ENC_REQ (0x05)
#define BLE_LL_CTRL_START_ENC_RSP (0x06)
#define BLE_LL_CTRL_UNKNOWN_RSP (0x07)
#define BLE_LL_CTRL_FEATURE_REQ (0x08)
#define BLE_LL_CTRL_FEATURE_RSP (0x09)
#define BLE_LL_CTRL_PAUSE_ENC_REQ (0x0A)
#define BLE_LL_CTRL_PAUSE_ENC_RSP (0x0B)
#define BLE_LL_CTRL_VERSION_IND (0x0C)
#define BLE_LL_CTRL_REJECT_IND (0x0D)
#define BLE_LL_CTRL_SLAVE_FEATURE_REQ (0x0E)
#define BLE_LL_CTRL_CONN_PARM_REQ (0x0F)
#define BLE_LL_CTRL_CONN_PARM_RSP (0x10)
#define BLE_LL_CTRL_REJECT_IND_EXT (0x11)
#define BLE_LL_CTRL_PING_REQ (0x12)
#define BLE_LL_CTRL_PING_RSP (0x13)
#define BLE_LL_CTRL_LENGTH_REQ (0x14)
#define BLE_LL_CTRL_LENGTH_RSP (0x15)
#define BLE_LL_CTRL_PHY_REQ (0x16)
#define BLE_LL_CTRL_PHY_RSP (0x17)
#define BLE_LL_CTRL_PHY_UPDATE_IND (0x18)
#define BLE_LL_CTRL_MIN_USED_CHAN_IND (0x19)
#define BLE_LL_CTRL_CTE_REQ (0x1A)
#define BLE_LL_CTRL_CTE_RSP (0x1B)
#define BLE_LL_CTRL_PERIODIC_SYNC_IND (0x1C)
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ (0x1D)
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP (0x1E)
#define BLE_LL_CTRL_CIS_REQ (0x1F)
#define BLE_LL_CTRL_CIS_RSP (0x20)
#define BLE_LL_CTRL_CIS_IND (0x21)
#define BLE_LL_CTRL_CIS_TERMINATE_IND (0x22)
/* Maximum opcode value */
#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_CLOCK_ACCURACY_RSP + 1)
#define BLE_LL_CTRL_OPCODES (BLE_LL_CTRL_CIS_TERMINATE_IND + 1)
extern const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES];
/* Maximum LL control PDU size */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
#if MYNEWT_VAL(BLE_ISO)
#define BLE_LL_CTRL_MAX_PDU_LEN (42)
#elif MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
#define BLE_LL_CTRL_MAX_PDU_LEN (35)
#else
#define BLE_LL_CTRL_MAX_PDU_LEN (27)
@@ -261,6 +269,12 @@ struct ble_ll_len_req
#define BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN (1)
#define BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN (1)
/* BLE ISO */
#define BLE_LL_CTRL_CIS_REQ_LEN (42)
#define BLE_LL_CTRL_CIS_RSP_LEN (8)
#define BLE_LL_CTRL_CIS_IND_LEN (15)
#define BLE_LL_CTRL_CIS_TERMINATE_LEN (3)
/* API */
struct ble_ll_conn_sm;
void ble_ll_ctrl_proc_start(struct ble_ll_conn_sm *connsm, int ctrl_proc);
@@ -306,6 +320,11 @@ void ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line);
uint8_t ble_ll_ctrl_phy_tx_transition_get(uint8_t phy_mask);
uint8_t ble_ll_ctrl_phy_from_phy_mask(uint8_t phy_mask);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
void ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm,
uint8_t status, uint8_t peer_sca);
#endif
#ifdef __cplusplus
}
#endif

View File

@@ -27,7 +27,7 @@ extern "C" {
#include "nimble/nimble/include/nimble/hci_common.h"
/* For supported commands */
#define BLE_LL_SUPP_CMD_LEN (42)
#define BLE_LL_SUPP_CMD_LEN (45)
extern const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN];
/* The largest event the controller will send. */

View File

@@ -0,0 +1,53 @@
/*
* 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 H_BLE_LL_ISO
#define H_BLE_LL_ISO
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
int ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd);
int ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len, uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_create_big(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_create_big_test(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_terminate_big(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -225,6 +225,8 @@ static inline int ble_ll_phy_to_phy_mode(int phy, int phy_options)
if (phy == BLE_PHY_CODED && phy_options == BLE_HCI_LE_PHY_CODED_S2_PREF) {
phy_mode = BLE_PHY_MODE_CODED_500KBPS;
}
#else
(void)phy_options;
#endif
return phy_mode;

View File

@@ -248,9 +248,6 @@ uint8_t g_dev_addr[BLE_DEV_ADDR_LEN];
/** Our random address */
uint8_t g_random_addr[BLE_DEV_ADDR_LEN];
/** Our supported features which can be controller by the host */
uint64_t g_ble_ll_supported_host_features = 0;
static const uint16_t g_ble_ll_pdu_header_tx_time[BLE_PHY_NUM_MODE] =
{
[BLE_PHY_MODE_1M] =
@@ -715,6 +712,7 @@ ble_ll_tx_pkt_in(void)
uint16_t pb;
struct os_mbuf_pkthdr *pkthdr;
struct os_mbuf *om;
os_sr_t sr;
/* Drain all packets off the queue */
while (STAILQ_FIRST(&g_ble_ll_data.ll_tx_pkt_q)) {
@@ -723,7 +721,9 @@ ble_ll_tx_pkt_in(void)
om = (struct os_mbuf *)((uint8_t *)pkthdr - sizeof(struct os_mbuf));
/* Remove from queue */
OS_ENTER_CRITICAL(sr);
STAILQ_REMOVE_HEAD(&g_ble_ll_data.ll_tx_pkt_q, omp_next);
OS_EXIT_CRITICAL(sr);
/* Strip HCI ACL header to get handle and length */
handle = get_le16(om->om_data);
@@ -1210,8 +1210,6 @@ ble_ll_task(void *arg)
/* Tell the host that we are ready to receive packets */
ble_ll_hci_send_noop();
ble_ll_rand_start();
while (1) {
ev = ble_npl_eventq_get(&g_ble_ll_data.ll_evq, BLE_NPL_TIME_FOREVER);
assert(ev);
@@ -1309,10 +1307,6 @@ ble_ll_set_host_feat(const uint8_t *cmdbuf, uint8_t len)
mask = (uint64_t)1 << (cmd->bit_num);
if (!(mask & BLE_LL_HOST_CONTROLLED_FEATURES)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (!(mask & g_ble_ll_supported_host_features)) {
return BLE_ERR_UNSUPPORTED;
}
@@ -1376,6 +1370,20 @@ ble_ll_mbuf_init(struct os_mbuf *m, uint8_t pdulen, uint8_t hdr)
ble_hdr->txinfo.hdr_byte = hdr;
}
static void
ble_ll_validate_task(void)
{
#ifdef MYNEWT
#ifndef NDEBUG
struct os_task_info oti;
os_task_info_get(&g_ble_ll_task, &oti);
BLE_LL_ASSERT(oti.oti_stkusage < oti.oti_stksize);
#endif
#endif
}
/**
* Called to reset the controller. This performs a "software reset" of the link
* layer; it does not perform a HW reset of the controller nor does it reset
@@ -1392,6 +1400,9 @@ ble_ll_reset(void)
int rc;
os_sr_t sr;
/* do sanity check on LL task stack */
ble_ll_validate_task();
OS_ENTER_CRITICAL(sr);
ble_phy_disable();
ble_ll_sched_stop();
@@ -1451,23 +1462,6 @@ ble_ll_reset(void)
return rc;
}
static void
ble_ll_seed_prng(void)
{
uint32_t seed;
int i;
/* Seed random number generator with least significant bytes of device
* address.
*/
seed = 0;
for (i = 0; i < 4; ++i) {
seed |= g_dev_addr[i];
seed <<= 8;
}
srand(seed);
}
uint32_t
ble_ll_pdu_tx_time_get(uint16_t payload_len, int phy_mode)
{
@@ -1685,16 +1679,24 @@ ble_ll_init(void)
features |= BLE_LL_FEAT_SYNC_TRANS_SEND;
#endif
/* Initialize random number generation */
ble_ll_rand_init();
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
features |= BLE_LL_FEAT_SCA_UPDATE;
#endif
/* XXX: This really doesn't belong here, as the address probably has not
* been set yet.
*/
ble_ll_seed_prng();
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
features |= BLE_LL_FEAT_CIS_MASTER;
features |= BLE_LL_FEAT_CIS_SLAVE;
features |= BLE_LL_FEAT_ISO_BROADCASTER;
features |= BLE_LL_FEAT_ISO_HOST_SUPPORT;
#endif
lldata->ll_supp_features = features;
/* Initialize random number generation */
ble_ll_rand_init();
/* Start the random number generator */
ble_ll_rand_start();
rc = stats_init_and_reg(STATS_HDR(ble_ll_stats),
STATS_SIZE_INIT_PARMS(ble_ll_stats, STATS_SIZE_32),
STATS_NAME_INIT_PARMS(ble_ll_stats),

View File

@@ -144,6 +144,7 @@ struct ble_ll_adv_sm
uint8_t aux_index : 1;
uint8_t aux_first_pdu : 1;
uint8_t aux_not_scanned : 1;
uint8_t aux_dropped : 1;
struct ble_mbuf_hdr *rx_ble_hdr;
struct os_mbuf **aux_data;
struct ble_ll_adv_aux aux[2];
@@ -698,7 +699,7 @@ ble_ll_adv_put_syncinfo(struct ble_ll_adv_sm *advsm,
dptr[8] = advsm->periodic_chanmap[4] & 0x1f;
/* SCA (3 bits) */
dptr[8] |= MYNEWT_VAL(BLE_LL_MASTER_SCA) << 5;
dptr[8] |= BLE_LL_SCA_ENUM << 5;
/* AA (4 bytes) */
put_le32(&dptr[9], advsm->periodic_access_addr);
@@ -1282,7 +1283,7 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch)
rc = ble_phy_tx_set_start_time(txstart, sch->remainder);
if (rc) {
STATS_INC(ble_ll_stats, adv_late_starts);
goto adv_tx_done;
goto adv_aux_dropped;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
@@ -1317,7 +1318,7 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch)
/* Transmit advertisement */
rc = ble_phy_tx(pducb, advsm, end_trans);
if (rc) {
goto adv_tx_done;
goto adv_aux_dropped;
}
/* Enable/disable whitelisting based on filter policy */
@@ -1335,7 +1336,8 @@ ble_ll_adv_secondary_tx_start_cb(struct ble_ll_sched_item *sch)
return BLE_LL_SCHED_STATE_RUNNING;
adv_tx_done:
adv_aux_dropped:
advsm->aux_dropped = 1;
ble_ll_adv_tx_done(advsm);
return BLE_LL_SCHED_STATE_DONE;
}
@@ -1390,7 +1392,7 @@ ble_ll_adv_aux_calculate(struct ble_ll_adv_sm *advsm,
g_ble_ll_conn_params.num_used_chans,
g_ble_ll_conn_params.master_chan_map);
#else
aux->chan = ble_ll_utils_remapped_channel(rand() % BLE_PHY_NUM_DATA_CHANS,
aux->chan = ble_ll_utils_remapped_channel(ble_ll_rand() % BLE_PHY_NUM_DATA_CHANS,
g_ble_ll_conn_params.master_chan_map);
#endif
@@ -1567,6 +1569,7 @@ ble_ll_adv_aux_schedule_first(struct ble_ll_adv_sm *advsm)
advsm->aux_index = 0;
advsm->aux_first_pdu = 1;
advsm->aux_not_scanned = 0;
advsm->aux_dropped = 0;
aux = AUX_CURRENT(advsm);
ble_ll_adv_aux_calculate(advsm, aux, 0);
@@ -1866,7 +1869,7 @@ ble_ll_adv_update_did(struct ble_ll_adv_sm *advsm)
* the previously used value.
*/
do {
advsm->adi = (advsm->adi & 0xf000) | (rand() & 0x0fff);
advsm->adi = (advsm->adi & 0xf000) | (ble_ll_rand() & 0x0fff);
} while (old_adi == advsm->adi);
}
#endif
@@ -2557,11 +2560,11 @@ ble_ll_adv_sm_start_periodic(struct ble_ll_adv_sm *advsm)
advsm->periodic_num_used_chans = g_ble_ll_conn_params.num_used_chans;
advsm->periodic_event_cntr = 0;
/* for chaining we start with random counter as we share access addr */
advsm->periodic_chain_event_cntr = rand();
advsm->periodic_chain_event_cntr = ble_ll_rand();
advsm->periodic_access_addr = ble_ll_utils_calc_access_addr();
advsm->periodic_channel_id = ((advsm->periodic_access_addr & 0xffff0000) >> 16) ^
(advsm->periodic_access_addr & 0x0000ffff);
advsm->periodic_crcinit = rand() & 0xffffff;
advsm->periodic_crcinit = ble_ll_rand() & 0xffffff;
usecs = (uint32_t)advsm->periodic_adv_itvl_max * BLE_LL_ADV_PERIODIC_ITVL;
ticks = os_cputime_usecs_to_ticks(usecs);
@@ -2750,7 +2753,7 @@ ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
*/
earliest_start_time = ble_ll_rfmgmt_enable_now();
start_delay_us = rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000);
start_delay_us = ble_ll_rand() % (BLE_LL_ADV_DELAY_MS_MAX * 1000);
advsm->adv_pdu_start_time = os_cputime_get32() +
os_cputime_usecs_to_ticks(start_delay_us);
@@ -4032,8 +4035,8 @@ ble_ll_adv_periodic_send_sync_ind(struct ble_ll_adv_sm *advsm,
/* SID, AType, SCA */
sync_ind[24] = (advsm->adi >> 12);
sync_ind[24] |= !!(advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) << 4 ;
sync_ind[24] |= MYNEWT_VAL(BLE_LL_MASTER_SCA) << 5;
sync_ind[24] |= !!(advsm->flags & BLE_LL_ADV_SM_FLAG_TX_ADD) << 4;
sync_ind[24] |= BLE_LL_SCA_ENUM << 5;
/* PHY */
sync_ind[25] = (0x01 << (advsm->sec_phy - 1));
@@ -4849,6 +4852,11 @@ ble_ll_adv_sec_done(struct ble_ll_adv_sm *advsm)
/* We don't need RF anymore */
ble_ll_rfmgmt_release();
if (advsm->aux_dropped) {
ble_ll_adv_drop_event(advsm);
return;
}
if (advsm->aux_not_scanned) {
ble_ll_sched_rmv_elem(&aux_next->sch);
}

View File

@@ -232,6 +232,166 @@ STATS_NAME_END(ble_ll_conn_stats)
static void ble_ll_conn_event_end(struct ble_npl_event *ev);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
struct ble_ll_conn_cth_flow {
bool enabled;
uint16_t max_buffers;
uint16_t num_buffers;
};
static struct ble_ll_conn_cth_flow g_ble_ll_conn_cth_flow;
static struct ble_npl_event g_ble_ll_conn_cth_flow_error_ev;
static bool
ble_ll_conn_cth_flow_is_enabled(void)
{
return g_ble_ll_conn_cth_flow.enabled;
}
static bool
ble_ll_conn_cth_flow_alloc_credit(struct ble_ll_conn_sm *connsm)
{
struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
if (!cth->num_buffers) {
OS_EXIT_CRITICAL(sr);
return false;
}
connsm->cth_flow_pending++;
cth->num_buffers--;
OS_EXIT_CRITICAL(sr);
return true;
}
static void
ble_ll_conn_cth_flow_free_credit(struct ble_ll_conn_sm *connsm, uint16_t credits)
{
struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow;
os_sr_t sr;
OS_ENTER_CRITICAL(sr);
/*
* It's not quite clear what we should do if host gives back more credits
* that we have allocated. For now let's just set invalid values back to
* sane values and continue.
*/
cth->num_buffers += credits;
if (cth->num_buffers > cth->max_buffers) {
cth->num_buffers = cth->max_buffers;
}
if (connsm->cth_flow_pending < credits) {
connsm->cth_flow_pending = 0;
} else {
connsm->cth_flow_pending -= credits;
}
OS_EXIT_CRITICAL(sr);
}
static void
ble_ll_conn_cth_flow_error_fn(struct ble_npl_event *ev)
{
struct ble_hci_ev *hci_ev;
struct ble_hci_ev_command_complete *hci_ev_cp;
uint16_t opcode;
hci_ev = (void *)ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (!hci_ev) {
/* Not much we can do anyway... */
return;
}
/*
* We are here in case length of HCI_Host_Number_Of_Completed_Packets was
* invalid. We will send an error back to host and we can only hope host is
* reasonable and will do some actions to recover, e.g. it should disconnect
* all connections to guarantee that all credits are back in pool and we're
* back in sync (although spec does not really say what should happen).
*/
opcode = BLE_HCI_OP(BLE_HCI_OGF_CTLR_BASEBAND,
BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS);
hci_ev->opcode = BLE_HCI_EVCODE_COMMAND_COMPLETE;
hci_ev->length = sizeof(*hci_ev_cp);
hci_ev_cp = (void *)hci_ev->data;
hci_ev_cp->num_packets = BLE_LL_CFG_NUM_HCI_CMD_PKTS;
hci_ev_cp->opcode = htole16(opcode);
hci_ev_cp->status = BLE_ERR_INV_HCI_CMD_PARMS;
ble_ll_hci_event_send(hci_ev);
}
void
ble_ll_conn_cth_flow_set_buffers(uint16_t num_buffers)
{
BLE_LL_ASSERT(num_buffers);
g_ble_ll_conn_cth_flow.max_buffers = num_buffers;
g_ble_ll_conn_cth_flow.num_buffers = num_buffers;
}
bool
ble_ll_conn_cth_flow_enable(bool enabled)
{
struct ble_ll_conn_cth_flow *cth = &g_ble_ll_conn_cth_flow;
if (cth->enabled == enabled) {
return true;
}
if (!SLIST_EMPTY(&g_ble_ll_conn_active_list)) {
return false;
}
cth->enabled = enabled;
return true;
}
void
ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf)
{
const struct ble_hci_cmd *cmd;
const struct ble_hci_cb_host_num_comp_pkts_cp *cp;
struct ble_ll_conn_sm *connsm;
int i;
cmd = (const void *)cmdbuf;
cp = (const void *)cmd->data;
if (cmd->length != sizeof(cp->handles) + cp->handles * sizeof(cp->h[0])) {
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, &g_ble_ll_conn_cth_flow_error_ev);
return;
}
for (i = 0; i < cp->handles; i++) {
/*
* It's probably ok that we do not have active connection with given
* handle - this can happen if disconnection already happened in LL but
* host sent credits back before processing disconnection event. In such
* case we can simply ignore command for that connection since credits
* are returned by LL already.
*/
connsm = ble_ll_conn_find_active_conn(cp->h[i].handle);
if (connsm) {
ble_ll_conn_cth_flow_free_credit(connsm, cp->h[i].count);
}
}
}
#endif
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
/**
* Checks to see if we should start a PHY update procedure
@@ -339,7 +499,7 @@ ble_ll_conn_is_lru(struct ble_ll_conn_sm *s1, struct ble_ll_conn_sm *s2)
int rc;
/* Set time that we last serviced the schedule */
if ((int32_t)(s1->last_scheduled - s2->last_scheduled) < 0) {
if (CPUTIME_LT(s1->last_scheduled, s2->last_scheduled)) {
rc = 1;
} else {
rc = 0;
@@ -862,8 +1022,14 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm)
/*
* If we are encrypting, we are only allowed to send certain
* kinds of LL control PDU's. If none is enqueued, send empty pdu!
*
* In Slave role, we are allowed to send unencrypted packets until
* LL_ENC_RSP is sent.
*/
if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) {
if (((connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) &&
CONN_IS_MASTER(connsm)) ||
((connsm->enc_data.enc_state > CONN_ENC_S_ENC_RSP_TO_BE_SENT) &&
CONN_IS_SLAVE(connsm))) {
if (!ble_ll_ctrl_enc_allowed_pdu_tx(pkthdr)) {
CONN_F_EMPTY_PDU_TXD(connsm) = 1;
goto conn_tx_pdu;
@@ -998,10 +1164,10 @@ ble_ll_conn_tx_pdu(struct ble_ll_conn_sm *connsm)
}
ticks = os_cputime_usecs_to_ticks(ticks);
if ((int32_t)((os_cputime_get32() + ticks) - next_event_time) < 0) {
if (CPUTIME_LT(os_cputime_get32() + ticks, next_event_time)) {
md = 1;
}
}
}
/* If we send an empty PDU we need to initialize the header */
conn_tx_pdu:
@@ -1457,10 +1623,10 @@ ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm)
*/
connsm->tx_win_size = BLE_LL_CONN_TX_WIN_MIN + 1;
connsm->tx_win_off = 0;
connsm->master_sca = MYNEWT_VAL(BLE_LL_MASTER_SCA);
connsm->master_sca = BLE_LL_SCA_ENUM;
/* Hop increment is a random value between 5 and 16. */
connsm->hop_inc = (rand() % 12) + 5;
connsm->hop_inc = (ble_ll_rand() % 12) + 5;
/* Set channel map to map requested by host */
connsm->num_used_chans = g_ble_ll_conn_params.num_used_chans;
@@ -1469,7 +1635,7 @@ ble_ll_conn_master_common_init(struct ble_ll_conn_sm *connsm)
/* Calculate random access address and crc initialization value */
connsm->access_addr = ble_ll_utils_calc_access_addr();
connsm->crcinit = rand() & 0xffffff;
connsm->crcinit = ble_ll_rand() & 0xffffff;
/* Set initial schedule callback */
connsm->conn_sch.sched_cb = ble_ll_conn_event_start_cb;
@@ -1868,6 +2034,10 @@ ble_ll_conn_end(struct ble_ll_conn_sm *connsm, uint8_t ble_err)
/* Remove from the active connection list */
SLIST_REMOVE(&g_ble_ll_conn_active_list, connsm, ble_ll_conn_sm, act_sle);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
ble_ll_conn_cth_flow_free_credit(connsm, connsm->cth_flow_pending);
#endif
/* Free the current transmit pdu if there is one. */
if (connsm->cur_tx_pdu) {
os_mbuf_free_chain(connsm->cur_tx_pdu);
@@ -3246,6 +3416,13 @@ ble_ll_init_rx_isr_end(uint8_t *rxbuf, uint8_t crcok,
*/
memcpy(init_addr, rl->rl_local_rpa, BLE_DEV_ADDR_LEN);
}
} else if (!ble_ll_is_rpa(adv_addr, adv_addr_type)) {
/* undirected with ID address, assure privacy if on RL */
rl = ble_ll_resolv_list_find(adv_addr, adv_addr_type);
if (rl && (rl->rl_priv_mode == BLE_HCI_PRIVACY_NETWORK) &&
rl->rl_has_peer) {
goto init_rx_isr_exit;
}
}
#endif
@@ -3459,129 +3636,142 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
uint16_t acl_hdr;
struct ble_ll_conn_sm *connsm;
if (BLE_MBUF_HDR_CRC_OK(hdr)) {
/* XXX: there is a chance that the connection was thrown away and
re-used before processing packets here. Fix this. */
/* We better have a connection state machine */
connsm = ble_ll_conn_find_active_conn(hdr->rxinfo.handle);
if (connsm) {
/* Check state machine */
ble_ll_conn_chk_csm_flags(connsm);
/* Packets with invalid CRC are not sent to LL */
BLE_LL_ASSERT(BLE_MBUF_HDR_CRC_OK(hdr));
/* Validate rx data pdu */
rxbuf = rxpdu->om_data;
hdr_byte = rxbuf[0];
acl_len = rxbuf[1];
llid = hdr_byte & BLE_LL_DATA_HDR_LLID_MASK;
/* XXX: there is a chance that the connection was thrown away and
re-used before processing packets here. Fix this. */
/* We better have a connection state machine */
connsm = ble_ll_conn_find_active_conn(hdr->rxinfo.handle);
if (!connsm) {
STATS_INC(ble_ll_conn_stats, no_conn_sm);
goto conn_rx_data_pdu_end;
}
/*
* Check that the LLID and payload length are reasonable.
* Empty payload is only allowed for LLID == 01b.
* */
if ((llid == 0) ||
((acl_len == 0) && (llid != BLE_LL_LLID_DATA_FRAG))) {
STATS_INC(ble_ll_conn_stats, rx_bad_llid);
goto conn_rx_data_pdu_end;
}
/* Check state machine */
ble_ll_conn_chk_csm_flags(connsm);
/* Validate rx data pdu */
rxbuf = rxpdu->om_data;
hdr_byte = rxbuf[0];
acl_len = rxbuf[1];
llid = hdr_byte & BLE_LL_DATA_HDR_LLID_MASK;
/*
* Check that the LLID and payload length are reasonable.
* Empty payload is only allowed for LLID == 01b.
* */
if ((llid == 0) || ((acl_len == 0) && (llid != BLE_LL_LLID_DATA_FRAG))) {
STATS_INC(ble_ll_conn_stats, rx_bad_llid);
goto conn_rx_data_pdu_end;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/* Check if PDU is allowed when encryption is started. If not,
* terminate connection.
*
* Reference: Core 5.0, Vol 6, Part B, 5.1.3.1
*/
if ((connsm->enc_data.enc_state > CONN_ENC_S_PAUSE_ENC_RSP_WAIT) &&
!ble_ll_ctrl_enc_allowed_pdu_rx(rxpdu)) {
ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC);
goto conn_rx_data_pdu_end;
}
/* Check if PDU is allowed when encryption is started. If not,
* terminate connection.
*
* Reference: Core 5.0, Vol 6, Part B, 5.1.3.1
*/
if ((connsm->enc_data.enc_state > CONN_ENC_S_PAUSE_ENC_RSP_WAIT &&
CONN_IS_MASTER(connsm)) ||
(connsm->enc_data.enc_state >= CONN_ENC_S_ENC_RSP_TO_BE_SENT &&
CONN_IS_SLAVE(connsm))) {
if (!ble_ll_ctrl_enc_allowed_pdu_rx(rxpdu)) {
ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC);
goto conn_rx_data_pdu_end;
}
}
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
/*
* Reset authenticated payload timeout if valid MIC. NOTE: we dont
* check the MIC failure bit as that would have terminated the
* connection
*/
if ((connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) &&
CONN_F_LE_PING_SUPP(connsm) && (acl_len != 0)) {
ble_ll_conn_auth_pyld_timer_start(connsm);
}
/*
* Reset authenticated payload timeout if valid MIC. NOTE: we dont
* check the MIC failure bit as that would have terminated the
* connection
*/
if ((connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) &&
CONN_F_LE_PING_SUPP(connsm) && (acl_len != 0)) {
ble_ll_conn_auth_pyld_timer_start(connsm);
}
#endif
/* Update RSSI */
connsm->conn_rssi = hdr->rxinfo.rssi;
/* Update RSSI */
connsm->conn_rssi = hdr->rxinfo.rssi;
/*
* If we are a slave, we can only start to use slave latency
* once we have received a NESN of 1 from the master
*/
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) {
connsm->csmflags.cfbit.allow_slave_latency = 1;
}
}
/*
* Discard the received PDU if the sequence number is the same
* as the last received sequence number
*/
rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
if (rxd_sn != connsm->last_rxd_sn) {
/* Update last rxd sn */
connsm->last_rxd_sn = rxd_sn;
/* No need to do anything if empty pdu */
if ((llid == BLE_LL_LLID_DATA_FRAG) && (acl_len == 0)) {
goto conn_rx_data_pdu_end;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/*
* XXX: should we check to see if we are in a state where we
* might expect to get an encrypted PDU?
*/
if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) {
STATS_INC(ble_ll_conn_stats, mic_failures);
ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC);
goto conn_rx_data_pdu_end;
}
#endif
if (llid == BLE_LL_LLID_CTRL) {
/* Process control frame */
STATS_INC(ble_ll_conn_stats, rx_ctrl_pdus);
if (ble_ll_ctrl_rx_pdu(connsm, rxpdu)) {
STATS_INC(ble_ll_conn_stats, rx_malformed_ctrl_pdus);
}
} else {
/* Count # of received l2cap frames and byes */
STATS_INC(ble_ll_conn_stats, rx_l2cap_pdus);
STATS_INCN(ble_ll_conn_stats, rx_l2cap_bytes, acl_len);
/* NOTE: there should be at least two bytes available */
BLE_LL_ASSERT(OS_MBUF_LEADINGSPACE(rxpdu) >= 2);
os_mbuf_prepend(rxpdu, 2);
rxbuf = rxpdu->om_data;
acl_hdr = (llid << 12) | connsm->conn_handle;
put_le16(rxbuf, acl_hdr);
put_le16(rxbuf + 2, acl_len);
ble_hci_trans_ll_acl_tx(rxpdu);
}
/* NOTE: we dont free the mbuf since we handed it off! */
return;
} else {
STATS_INC(ble_ll_conn_stats, data_pdu_rx_dup);
}
} else {
STATS_INC(ble_ll_conn_stats, no_conn_sm);
/*
* If we are a slave, we can only start to use slave latency
* once we have received a NESN of 1 from the master
*/
if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) {
if (hdr_byte & BLE_LL_DATA_HDR_NESN_MASK) {
connsm->csmflags.cfbit.allow_slave_latency = 1;
}
}
/*
* Discard the received PDU if the sequence number is the same
* as the last received sequence number
*/
rxd_sn = hdr_byte & BLE_LL_DATA_HDR_SN_MASK;
if (rxd_sn == connsm->last_rxd_sn) {
STATS_INC(ble_ll_conn_stats, data_pdu_rx_dup);
goto conn_rx_data_pdu_end;
}
/* Update last rxd sn */
connsm->last_rxd_sn = rxd_sn;
/* No need to do anything if empty pdu */
if ((llid == BLE_LL_LLID_DATA_FRAG) && (acl_len == 0)) {
goto conn_rx_data_pdu_end;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_ENCRYPTION)
/*
* XXX: should we check to see if we are in a state where we
* might expect to get an encrypted PDU?
*/
if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) {
STATS_INC(ble_ll_conn_stats, mic_failures);
ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC);
goto conn_rx_data_pdu_end;
}
#endif
if (llid == BLE_LL_LLID_CTRL) {
/* Process control frame */
STATS_INC(ble_ll_conn_stats, rx_ctrl_pdus);
if (ble_ll_ctrl_rx_pdu(connsm, rxpdu)) {
STATS_INC(ble_ll_conn_stats, rx_malformed_ctrl_pdus);
}
} else {
/* Count # of received l2cap frames and byes */
STATS_INC(ble_ll_conn_stats, rx_l2cap_pdus);
STATS_INCN(ble_ll_conn_stats, rx_l2cap_bytes, acl_len);
/* NOTE: there should be at least two bytes available */
BLE_LL_ASSERT(OS_MBUF_LEADINGSPACE(rxpdu) >= 2);
os_mbuf_prepend(rxpdu, 2);
rxbuf = rxpdu->om_data;
acl_hdr = (llid << 12) | connsm->conn_handle;
put_le16(rxbuf, acl_hdr);
put_le16(rxbuf + 2, acl_len);
ble_hci_trans_ll_acl_tx(rxpdu);
}
/* NOTE: we dont free the mbuf since we handed it off! */
return;
/* Free buffer */
conn_rx_data_pdu_end:
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
/* Need to give credit back if we allocated one for this PDU */
if (hdr->rxinfo.flags & BLE_MBUF_HDR_F_CONN_CREDIT) {
ble_ll_conn_cth_flow_free_credit(connsm, 1);
}
#endif
os_mbuf_free_chain(rxpdu);
}
@@ -3602,7 +3792,6 @@ int
ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
{
int rc;
int is_ctrl;
uint8_t hdr_byte;
uint8_t hdr_sn;
uint8_t hdr_nesn;
@@ -3616,14 +3805,43 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
uint32_t add_usecs;
struct os_mbuf *txpdu;
struct ble_ll_conn_sm *connsm;
struct os_mbuf *rxpdu;
struct os_mbuf *rxpdu = NULL;
struct ble_mbuf_hdr *txhdr;
int rx_phy_mode;
bool alloc_rxpdu = true;
rc = -1;
connsm = g_ble_ll_conn_cur_sm;
/* Retrieve the header and payload length */
hdr_byte = rxbuf[0];
rx_pyld_len = rxbuf[1];
/*
* No need to alloc rxpdu for packets with invalid CRC, we would throw them
* away instantly from LL anyway.
*/
if (!BLE_MBUF_HDR_CRC_OK(rxhdr)) {
alloc_rxpdu = false;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
/*
* If flow control is enabled, we need to have credit available for each
* non-empty data packet that LL may send to host. If there are no credits
* available, we don't need to allocate buffer for this packet so LL will
* nak it.
*/
if (alloc_rxpdu && ble_ll_conn_cth_flow_is_enabled() &&
BLE_LL_LLID_IS_DATA(hdr_byte) && (rx_pyld_len > 0)) {
if (ble_ll_conn_cth_flow_alloc_credit(connsm)) {
rxhdr->rxinfo.flags |= BLE_MBUF_HDR_F_CONN_CREDIT;
} else {
alloc_rxpdu = false;
}
}
#endif
/*
* We need to attempt to allocate a buffer here. The reason we do this
* now is that we should not ack the packet if we have no receive
@@ -3631,14 +3849,14 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
* acked, but we should not ack the received frame if we cant hand it up.
* NOTE: we hand up empty pdu's to the LL task!
*/
rxpdu = ble_ll_rxpdu_alloc(rx_pyld_len + BLE_LL_PDU_HDR_LEN);
if (alloc_rxpdu) {
rxpdu = ble_ll_rxpdu_alloc(rx_pyld_len + BLE_LL_PDU_HDR_LEN);
}
/*
* We should have a current connection state machine. If we dont, we just
* hand the packet to the higher layer to count it.
*/
rc = -1;
connsm = g_ble_ll_conn_cur_sm;
if (!connsm) {
STATS_INC(ble_ll_conn_stats, rx_data_pdu_no_conn);
goto conn_exit;
@@ -3700,9 +3918,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
/* Set last received header byte */
connsm->last_rxd_hdr_byte = hdr_byte;
is_ctrl = 0;
if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) {
is_ctrl = 1;
if (BLE_LL_LLID_IS_CTRL(hdr_byte)) {
opcode = rxbuf[2];
}
@@ -3791,7 +4007,7 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
/* Adjust payload for max TX time and octets */
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
if (is_ctrl &&
if (BLE_LL_LLID_IS_CTRL(hdr_byte) &&
(connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) &&
(opcode == BLE_LL_CTRL_PHY_UPDATE_IND)) {
connsm->phy_tx_transition =
@@ -3810,8 +4026,9 @@ ble_ll_conn_rx_isr_end(uint8_t *rxbuf, struct ble_mbuf_hdr *rxhdr)
/* If this is a TERMINATE_IND, we have to reply */
chk_rx_terminate_ind:
/* If we received a terminate IND, we must set some flags */
if (is_ctrl && (opcode == BLE_LL_CTRL_TERMINATE_IND)
&& (rx_pyld_len == (1 + BLE_LL_CTRL_TERMINATE_IND_LEN))) {
if (BLE_LL_LLID_IS_CTRL(hdr_byte) &&
(opcode == BLE_LL_CTRL_TERMINATE_IND) &&
(rx_pyld_len == (1 + BLE_LL_CTRL_TERMINATE_IND_LEN))) {
connsm->csmflags.cfbit.terminate_ind_rxd = 1;
connsm->rxd_disconnect_reason = rxbuf[3];
}
@@ -4233,6 +4450,12 @@ ble_ll_conn_module_reset(void)
g_ble_ll_conn_sync_transfer_params.mode = 0;
g_ble_ll_conn_sync_transfer_params.sync_timeout_us = 0;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
g_ble_ll_conn_cth_flow.enabled = false;
g_ble_ll_conn_cth_flow.max_buffers = 1;
g_ble_ll_conn_cth_flow.num_buffers = 1;
#endif
}
/* Initialize the connection module */
@@ -4272,6 +4495,11 @@ ble_ll_conn_module_init(void)
"ble_ll_conn");
BLE_LL_ASSERT(rc == 0);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
ble_npl_event_init(&g_ble_ll_conn_cth_flow_error_ev,
ble_ll_conn_cth_flow_error_fn, NULL);
#endif
/* Call reset to finish reset of initialization */
ble_ll_conn_module_reset();
}

View File

@@ -1129,16 +1129,11 @@ ble_ll_conn_create_cancel(ble_ll_hci_post_cmd_complete_cb *post_cmd_cb)
* @return int
*/
int
ble_ll_conn_hci_disconnect_cmd(const uint8_t *cmdbuf, uint8_t len)
ble_ll_conn_hci_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd)
{
int rc;
uint16_t handle;
struct ble_ll_conn_sm *connsm;
const struct ble_hci_lc_disconnect_cp *cmd = (const void *) cmdbuf;
if (len != sizeof (*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* Check for valid parameters */
handle = le16toh(cmd->conn_handle);
@@ -1566,6 +1561,34 @@ ltk_key_cmd_complete:
}
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
int
ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
const struct ble_hci_le_request_peer_sca_cp *params = (const void *)cmdbuf;
struct ble_ll_conn_sm *connsm;
connsm = ble_ll_conn_find_active_conn(params->conn_handle);
if (!connsm) {
return BLE_ERR_UNK_CONN_ID;
}
if (!(connsm->remote_features[2] & (BLE_LL_FEAT_SCA_UPDATE >> 24))) {
return BLE_ERR_UNSUPP_REM_FEATURE;
}
if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE)) {
/* Not really specified what we should return */
return BLE_ERR_CTLR_BUSY;
}
ble_ll_ctrl_proc_start(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE);
return 0;
}
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
/**
* Read authenticated payload timeout (OGF=3, OCF==0x007B)

View File

@@ -164,7 +164,7 @@ bool ble_ll_conn_init_pending_aux_conn_rsp(void);
void ble_ll_disconn_comp_event_send(struct ble_ll_conn_sm *connsm,
uint8_t reason);
void ble_ll_auth_pyld_tmo_event_send(struct ble_ll_conn_sm *connsm);
int ble_ll_conn_hci_disconnect_cmd(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd);
int ble_ll_conn_hci_rd_rem_ver_cmd(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_create(const uint8_t *cmdbuf, uint8_t len);
int ble_ll_conn_hci_update(const uint8_t *cmdbuf, uint8_t len);
@@ -196,12 +196,23 @@ int ble_ll_conn_hci_wr_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
int ble_ll_conn_hci_rd_auth_pyld_tmo(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
int ble_ll_conn_req_peer_sca(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen);
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LE_PING)
void ble_ll_conn_auth_pyld_timer_start(struct ble_ll_conn_sm *connsm);
#else
#define ble_ll_conn_auth_pyld_timer_start(x)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
void ble_ll_conn_cth_flow_set_buffers(uint16_t num_buffers);
bool ble_ll_conn_cth_flow_enable(bool enabled);
void ble_ll_conn_cth_flow_process_cmd(const uint8_t *cmdbuf);
#endif
int ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg);
int ble_ll_hci_acl_rx(struct os_mbuf *om, void *arg);

View File

@@ -114,6 +114,10 @@ const uint8_t g_ble_ll_ctrl_pkt_lengths[BLE_LL_CTRL_OPCODES] =
BLE_LL_CTRL_PERIODIC_SYNC_IND_LEN,
BLE_LL_CTRL_CLOCK_ACCURACY_REQ_LEN,
BLE_LL_CTRL_CLOCK_ACCURACY_RSP_LEN,
BLE_LL_CTRL_CIS_REQ_LEN,
BLE_LL_CTRL_CIS_RSP_LEN,
BLE_LL_CTRL_CIS_IND_LEN,
BLE_LL_CTRL_CIS_TERMINATE_LEN
};
/**
@@ -508,6 +512,12 @@ ble_ll_ctrl_proc_unk_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr, uint8_t *
ble_ll_ctrl_phy_update_cancel(connsm, BLE_ERR_UNSUPP_REM_FEATURE);
ctrl_proc = BLE_LL_CTRL_PROC_PHY_UPDATE;
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
case BLE_LL_CTRL_CLOCK_ACCURACY_REQ:
ble_ll_hci_ev_sca_update(connsm, BLE_ERR_UNSUPPORTED, 0);
ctrl_proc = BLE_LL_CTRL_PROC_SCA_UPDATE;
break;
#endif
default:
ctrl_proc = BLE_LL_CTRL_PROC_NUM;
@@ -839,6 +849,20 @@ ble_ll_ctrl_phy_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata)
}
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
/**
* Create a LL_CLOCK_ACCURACY_REQ or LL_CLOCK_ACCURACY_RSP pdu
*
* @param connsm Pointer to connection state machine
* @param ctrdata: Pointer to where CtrData starts in pdu
*/
static void
ble_ll_ctrl_sca_req_rsp_make(struct ble_ll_conn_sm *connsm, uint8_t *ctrdata)
{
ctrdata[0] = BLE_LL_SCA_ENUM;
}
#endif
static uint8_t
ble_ll_ctrl_rx_phy_req(struct ble_ll_conn_sm *connsm, uint8_t *req,
uint8_t *rsp)
@@ -1043,11 +1067,70 @@ ble_ll_ctrl_rx_periodic_sync_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
connsm->sync_transfer_skip,
connsm->sync_transfer_sync_timeout);
}
return BLE_ERR_MAX;
}
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
/**
* Called when a BLE_LL_CTRL_CLOCK_ACCURACY_REQ PDU is received
*
* @param connsm
* @param dptr
* @param rsp Pointer to CtrData of BLE_LL_CTRL_CLOCK_ACCURACY_RSP.
*
* @return uint8_t
*/
static uint8_t
ble_ll_ctrl_rx_sca_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
uint8_t *rsp)
{
ble_ll_ctrl_sca_req_rsp_make(connsm, rsp);
return BLE_LL_CTRL_CLOCK_ACCURACY_RSP;
}
/**
* Called when a BLE_LL_CTRL_CLOCK_ACCURACY_RSP PDU is received
*
* @param connsm
* @param dptr
*
* @return uint8_t
*/
static uint8_t
ble_ll_ctrl_rx_sca_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
{
if (connsm->cur_ctrl_proc != BLE_LL_CTRL_PROC_SCA_UPDATE) {
return BLE_LL_CTRL_UNKNOWN_RSP;
}
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE);
ble_ll_hci_ev_sca_update(connsm, BLE_ERR_SUCCESS, dptr[0]);
return BLE_ERR_MAX;
}
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
static uint8_t
ble_ll_ctrl_rx_cis_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
uint8_t *rspdata)
{
return BLE_LL_CTRL_UNKNOWN_RSP;
}
static uint8_t
ble_ll_ctrl_rx_cis_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
uint8_t *rspdata)
{
return BLE_LL_CTRL_UNKNOWN_RSP;
}
static uint8_t
ble_ll_ctrl_rx_cis_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
{
return BLE_LL_CTRL_UNKNOWN_RSP;
}
#endif
/**
* Create a link layer length request or length response PDU.
*
@@ -1253,6 +1336,15 @@ ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm)
return rc;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
static void
ble_ll_ctrl_cis_create(struct ble_ll_conn_sm *connsm, uint8_t *dptr)
{
/* TODO Implement */
return;
}
#endif
/**
* Create a link layer control "encrypt request" PDU.
*
@@ -1354,7 +1446,7 @@ ble_ll_ctrl_rx_enc_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
return BLE_LL_CTRL_UNKNOWN_RSP;
}
connsm->enc_data.enc_state = CONN_ENC_S_LTK_REQ_WAIT;
connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_TO_BE_SENT;
/* In case we were already encrypted we need to reset packet counters */
connsm->enc_data.rx_pkt_cntr = 0;
@@ -1679,6 +1771,12 @@ ble_ll_ctrl_rx_reject_ind(struct ble_ll_conn_sm *connsm, uint8_t *dptr,
*/
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_DATA_LEN_UPD);
break;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
case BLE_LL_CTRL_PROC_SCA_UPDATE:
ble_ll_hci_ev_sca_update(connsm, ble_error, 0);
ble_ll_ctrl_proc_stop(connsm, BLE_LL_CTRL_PROC_SCA_UPDATE);
break;
#endif
default:
break;
}
@@ -2141,6 +2239,18 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc)
opcode = BLE_LL_CTRL_PHY_REQ;
ble_ll_ctrl_phy_req_rsp_make(connsm, ctrdata);
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
case BLE_LL_CTRL_PROC_SCA_UPDATE:
opcode = BLE_LL_CTRL_CLOCK_ACCURACY_REQ;
ble_ll_ctrl_sca_req_rsp_make(connsm, ctrdata);
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
case BLE_LL_CTRL_PROC_CIS_CREATE:
opcode = BLE_LL_CTRL_CIS_REQ;
ble_ll_ctrl_cis_create(connsm, ctrdata);
break;
#endif
default:
BLE_LL_ASSERT(0);
@@ -2571,6 +2681,26 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om)
rsp_opcode = ble_ll_ctrl_rx_phy_update_ind(connsm, dptr);
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
case BLE_LL_CTRL_CLOCK_ACCURACY_REQ:
rsp_opcode = ble_ll_ctrl_rx_sca_req(connsm, dptr, rspdata);
break;
case BLE_LL_CTRL_CLOCK_ACCURACY_RSP:
rsp_opcode = ble_ll_ctrl_rx_sca_rsp(connsm, dptr);
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
case BLE_LL_CTRL_CIS_REQ:
rsp_opcode = ble_ll_ctrl_rx_cis_req(connsm, dptr, rspdata);
break;
case BLE_LL_CTRL_CIS_RSP:
rsp_opcode = ble_ll_ctrl_rx_cis_rsp(connsm, dptr, rspdata);
break;
case BLE_LL_CTRL_CIS_IND:
rsp_opcode = ble_ll_ctrl_rx_cis_ind(connsm, dptr);
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PERIODIC_ADV_SYNC_TRANSFER)
case BLE_LL_CTRL_PERIODIC_SYNC_IND:
rsp_opcode = ble_ll_ctrl_rx_periodic_sync_ind(connsm, dptr);
@@ -2712,6 +2842,7 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm)
connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_WAIT;
break;
case BLE_LL_CTRL_ENC_RSP:
connsm->enc_data.enc_state = CONN_ENC_S_LTK_REQ_WAIT;
connsm->csmflags.cfbit.send_ltk_req = 1;
break;
case BLE_LL_CTRL_START_ENC_RSP:

View File

@@ -35,6 +35,7 @@
#include "../include/controller/ble_ll_whitelist.h"
#include "../include/controller/ble_ll_resolv.h"
#include "../include/controller/ble_ll_sync.h"
#include "../include/controller/ble_ll_iso.h"
#include "ble_ll_priv.h"
#include "ble_ll_conn_priv.h"
@@ -329,6 +330,31 @@ ble_ll_hci_le_read_bufsize(uint8_t *rspbuf, uint8_t *rsplen)
return BLE_ERR_SUCCESS;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
/**
* HCI read buffer size v2 command. Returns the ACL and ISO data packet length and
* num data packets.
*
* @param rspbuf Pointer to response buffer
* @param rsplen Length of response buffer
*
* @return int BLE error code
*/
static int
ble_ll_hci_le_read_bufsize_v2(uint8_t *rspbuf, uint8_t *rsplen)
{
struct ble_hci_le_rd_buf_size_v2_rp *rp = (void *) rspbuf;
rp->data_len = htole16(g_ble_ll_data.ll_acl_pkt_size);
rp->data_packets = g_ble_ll_data.ll_num_acl_pkts;
rp->iso_data_len = 0;
rp->iso_data_packets = 0;
*rsplen = sizeof(*rp);
return BLE_ERR_SUCCESS;
}
#endif
#if (BLE_LL_BT5_PHY_SUPPORTED == 1)
/**
* Checks the preferred phy masks for validity and places the preferred masks
@@ -620,6 +646,9 @@ ble_ll_hci_le_cmd_send_cmd_status(uint16_t ocf)
case BLE_HCI_OCF_LE_GEN_DHKEY:
case BLE_HCI_OCF_LE_SET_PHY:
case BLE_HCI_OCF_LE_PERIODIC_ADV_CREATE_SYNC:
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
case BLE_HCI_OCF_LE_REQ_PEER_SCA:
#endif
rc = 1;
break;
default:
@@ -1151,10 +1180,77 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf,
rc = ble_ll_set_default_sync_transfer_params(cmdbuf, len);
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
case BLE_HCI_OCF_LE_READ_ISO_TX_SYNC:
rc = ble_ll_iso_read_tx_sync(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_SET_CIG_PARAM:
rc = ble_ll_iso_set_cig_param(cmdbuf, len, rspbuf, rsplen);
break;
case BLE_HCI_OCF_LE_CREATE_CIS:
rc = ble_ll_iso_create_cis(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_REMOVE_CIG:
rc = ble_ll_iso_remove_cig(cmdbuf, len, rspbuf, rsplen);
break;
case BLE_HCI_OCF_LE_ACCEPT_CIS_REQ:
rc = ble_ll_iso_accept_cis_req(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_REJECT_CIS_REQ:
rc = ble_ll_iso_reject_cis_req(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_CREATE_BIG:
rc = ble_ll_iso_create_big(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_TERMINATE_BIG:
rc = ble_ll_iso_terminate_big(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_BIG_CREATE_SYNC:
rc = ble_ll_iso_big_create_sync(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_BIG_TERMINATE_SYNC:
rc = ble_ll_iso_big_terminate_sync(cmdbuf,len);
break;
case BLE_HCI_OCF_LE_SETUP_ISO_DATA_PATH:
rc = ble_ll_iso_setup_iso_data_path(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_REMOVE_ISO_DATA_PATH:
rc = ble_ll_iso_remove_iso_data_path(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_RD_BUF_SIZE_V2:
rc = ble_ll_hci_le_read_bufsize_v2(rspbuf, rsplen);
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST)
case BLE_HCI_OCF_LE_SET_CIG_PARAM_TEST:
rc = ble_ll_iso_set_cig_param_test(cmdbuf, len, rspbuf, rsplen);
break;
case BLE_HCI_OCF_LE_CREATE_BIG_TEST:
rc = ble_ll_iso_create_big_test(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_ISO_TRANSMIT_TEST:
rc = ble_ll_iso_transmit_test(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_ISO_RECEIVE_TEST:
rc = ble_ll_iso_receive_test(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_ISO_READ_TEST_COUNTERS:
rc = ble_ll_iso_read_counters_test(cmdbuf, len);
break;
case BLE_HCI_OCF_LE_ISO_TEST_END:
rc = ble_ll_iso_end_test(cmdbuf, len);
break;
#endif
#if MYNEWT_VAL(BLE_VERSION) >= 52
case BLE_HCI_OCF_LE_SET_HOST_FEAT:
rc = ble_ll_set_host_feat(cmdbuf, len);
break;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
case BLE_HCI_OCF_LE_REQ_PEER_SCA:
rc = ble_ll_conn_req_peer_sca(cmdbuf, len,
rspbuf, rsplen);
break;
#endif
default:
rc = BLE_ERR_UNKNOWN_HCI_CMD;
@@ -1176,6 +1272,26 @@ ble_ll_hci_le_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf,
return rc;
}
static int
ble_ll_hci_disconnect(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_lc_disconnect_cp *cmd;
cmd = (const void *) cmdbuf;
if (len != sizeof (*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
if (le16toh(cmd->conn_handle) >= BLE_LL_CONN_HANDLE_ISO_OFFSET) {
return ble_ll_iso_disconnect_cmd(cmd);
}
#endif
return ble_ll_conn_hci_disconnect_cmd(cmd);
}
/**
* Process a link control command sent from the host to the controller. The HCI
* command has a 3 byte command header followed by data. The header is:
@@ -1196,7 +1312,7 @@ ble_ll_hci_link_ctrl_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf)
switch (ocf) {
case BLE_HCI_OCF_DISCONNECT_CMD:
rc = ble_ll_conn_hci_disconnect_cmd(cmdbuf, len);
rc = ble_ll_hci_disconnect(cmdbuf, len);
/* Send command status instead of command complete */
rc += (BLE_ERR_MAX + 1);
break;
@@ -1229,6 +1345,64 @@ ble_ll_hci_cb_set_event_mask(const uint8_t *cmdbuf, uint8_t len)
return BLE_ERR_SUCCESS;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
static int
ble_ll_hci_cb_set_ctrlr_to_host_fc(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_cb_ctlr_to_host_fc_cp *cmd = (const void *) cmdbuf;
if (len != sizeof (*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* We only allow to either disable flow control or enable for ACL only */
if (cmd->enable > 1) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
if (!ble_ll_conn_cth_flow_enable(cmd->enable)) {
return BLE_ERR_CMD_DISALLOWED;
}
return BLE_ERR_SUCCESS;
}
static int
ble_ll_hci_cb_host_buf_size(const uint8_t *cmdbuf, uint8_t len)
{
const struct ble_hci_cb_host_buf_size_cp *cmd = (const void *) cmdbuf;
uint16_t acl_num;
uint16_t acl_data_len;
if (len != sizeof (*cmd)) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/* We do not support SCO so those parameters should be set to 0 */
if (cmd->sco_num || cmd->sco_data_len) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
/*
* Core 5.2 Vol 4 Part E section 7.3.39 states that "Both the Host and the
* Controller shall support command and event packets, where the data portion
* (excluding header) contained in the packets is 255 octets in size.".
* This means we can basically accept any allowed value since LL does not
* reassemble incoming data thus will not send more than 255 octets in single
* data packet.
*/
acl_num = le16toh(cmd->acl_num);
acl_data_len = le16toh(cmd->acl_data_len);
if (acl_data_len < 255) {
return BLE_ERR_INV_HCI_CMD_PARMS;
}
ble_ll_conn_cth_flow_set_buffers(acl_num);
return BLE_ERR_SUCCESS;
}
#endif
static int
ble_ll_hci_cb_set_event_mask2(const uint8_t *cmdbuf, uint8_t len)
{
@@ -1261,6 +1435,22 @@ ble_ll_hci_ctlr_bb_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf,
rc = ble_ll_reset();
}
break;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
case BLE_HCI_OCF_CB_SET_CTLR_TO_HOST_FC:
rc = ble_ll_hci_cb_set_ctrlr_to_host_fc(cmdbuf, len);
break;
case BLE_HCI_OCF_CB_HOST_BUF_SIZE:
rc = ble_ll_hci_cb_host_buf_size(cmdbuf, len);
break;
case BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS:
/*
* HCI_Host_Number_Of_Completed_Packets is handled immediately when
* received from transport so we should never receive it here.
*/
BLE_LL_ASSERT(0);
rc = BLE_ERR_UNKNOWN_HCI_CMD;
break;
#endif
case BLE_HCI_OCF_CB_SET_EVENT_MASK2:
rc = ble_ll_hci_cb_set_event_mask2(cmdbuf, len);
break;
@@ -1337,6 +1527,47 @@ ble_ll_hci_status_params_cmd_proc(const uint8_t *cmdbuf, uint8_t len,
return rc;
}
#if MYNEWT_VAL(BLE_HCI_VS)
static int
ble_ll_hci_vs_rd_static_addr(uint8_t *rspbuf, uint8_t *rsplen)
{
struct ble_hci_vs_rd_static_addr_rp *rsp = (void *) rspbuf;
ble_addr_t addr;
if (ble_hw_get_static_addr(&addr) < 0) {
return BLE_ERR_UNSPECIFIED;
}
memcpy(rsp->addr, addr.val, sizeof(rsp->addr));
*rsplen = sizeof(*rsp);
return BLE_ERR_SUCCESS;
}
static int
ble_ll_hci_vs_cmd_proc(const uint8_t *cmdbuf, uint8_t len, uint16_t ocf,
uint8_t *rspbuf, uint8_t *rsplen)
{
int rc;
/* Assume error; if all pass rc gets set to 0 */
rc = BLE_ERR_INV_HCI_CMD_PARMS;
switch (ocf) {
case BLE_HCI_OCF_VS_RD_STATIC_ADDR:
if (len == 0) {
rc = ble_ll_hci_vs_rd_static_addr(rspbuf, rsplen);
}
break;
default:
rc = BLE_ERR_UNKNOWN_HCI_CMD;
break;
}
return rc;
}
#endif
/**
* Called to process an HCI command from the host.
*
@@ -1396,6 +1627,11 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev)
case BLE_HCI_OGF_LE:
rc = ble_ll_hci_le_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen, &post_cb);
break;
#if MYNEWT_VAL(BLE_HCI_VS)
case BLE_HCI_OGF_VENDOR:
rc = ble_ll_hci_vs_cmd_proc(cmd->data, cmd->length, ocf, rspbuf, &rsplen);
break;
#endif
default:
/* XXX: Need to support other OGF. For now, return unsupported */
rc = BLE_ERR_UNKNOWN_HCI_CMD;
@@ -1456,9 +1692,33 @@ ble_ll_hci_cmd_proc(struct ble_npl_event *ev)
* BLE_ERR_MEM_CAPACITY on HCI buffer exhaustion.
*/
int
ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg)
ble_ll_hci_cmd_rx(uint8_t *cmdbuf, void *arg)
{
struct ble_npl_event *ev;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
const struct ble_hci_cmd *cmd;
uint16_t opcode;
uint16_t ocf;
uint16_t ogf;
cmd = (const void *)cmdbuf;
opcode = le16toh(cmd->opcode);
ogf = BLE_HCI_OGF(opcode);
ocf = BLE_HCI_OCF(opcode);
/*
* HCI_Host_Number_Of_Completed_Packets is processed outside standard flow
* thus it can be sent at any time, even if another command is already
* pending. This means we should better process it here and send an event to
* LL in case of error.
*/
if ((ogf == BLE_HCI_OGF_CTLR_BASEBAND) &&
(ocf == BLE_HCI_OCF_CB_HOST_NUM_COMP_PKTS)) {
ble_ll_conn_cth_flow_process_cmd(cmdbuf);
ble_hci_trans_buf_free(cmdbuf);
return 0;
}
#endif
/* Get an event structure off the queue */
ev = &g_ble_ll_hci_cmd_ev;
@@ -1467,7 +1727,7 @@ ble_ll_hci_cmd_rx(uint8_t *cmd, void *arg)
}
/* Fill out the event and post to Link Layer */
ble_npl_event_set_arg(ev, cmd);
ble_npl_event_set_arg(ev, cmdbuf);
ble_npl_eventq_put(&g_ble_ll_data.ll_evq, ev);
return 0;

View File

@@ -463,6 +463,37 @@ ble_ll_hci_ev_phy_update(struct ble_ll_conn_sm *connsm, uint8_t status)
}
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
void
ble_ll_hci_ev_sca_update(struct ble_ll_conn_sm *connsm, uint8_t status,
uint8_t peer_sca)
{
struct ble_hci_ev_le_subev_peer_sca_complete *ev;
struct ble_hci_ev *hci_ev;
if (!ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_REQ_PEER_SCA_COMP)) {
return;
}
hci_ev = (void *) ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_EVT_HI);
if (!hci_ev) {
return;
}
hci_ev->opcode = BLE_HCI_EVCODE_LE_META;
hci_ev->length = sizeof(*ev);
ev = (void *) hci_ev->data;
ev->subev_code = BLE_HCI_LE_SUBEV_REQ_PEER_SCA_COMP;
ev->status = status;
ev->conn_handle = htole16(connsm->conn_handle);
ev->sca = peer_sca;
ble_ll_hci_event_send(hci_ev);
}
#endif
void
ble_ll_hci_ev_send_vendor_err(const char *file, uint32_t line)
{

View File

@@ -0,0 +1,147 @@
/*
* 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 ESP_PLATFORM
#include <stdint.h>
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "nimble/nimble/include/nimble/ble.h"
#include "nimble/nimble/include/nimble/hci_common.h"
#include "../include/controller/ble_ll_iso.h"
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
int
ble_ll_iso_read_tx_sync(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_set_cig_param(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_create_cis(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_disconnect_cmd(const struct ble_hci_lc_disconnect_cp *cmd)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_remove_cig(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_accept_cis_req(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_reject_cis_req(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_setup_iso_data_path(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_remove_iso_data_path(const uint8_t *cmdbuf, uint8_t len)
{
/* Nothing to do here for now when HCI is supported */
return 0;
}
int
ble_ll_iso_create_big(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_terminate_big(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_big_create_sync(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_big_terminate_sync(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO_TEST)
int
ble_ll_iso_set_cig_param_test(const uint8_t *cmdbuf, uint8_t len,
uint8_t *rspbuf, uint8_t *rsplen)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_create_big_test(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_transmit_test(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_receive_test(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_read_counters_test(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
int
ble_ll_iso_end_test(const uint8_t *cmdbuf, uint8_t len)
{
return BLE_ERR_UNSUPPORTED;
}
#endif
#endif
#endif

View File

@@ -18,6 +18,9 @@
*/
#ifndef ESP_PLATFORM
/* for jrand48 */
#define _XOPEN_SOURCE
#include <stdlib.h>
#include <stdint.h>
#include <assert.h>
#include <string.h>
@@ -121,6 +124,21 @@ ble_ll_rand_data_get(uint8_t *buf, uint8_t len)
return BLE_ERR_SUCCESS;
}
/* Simple wrapper to allow easy replacement of rand() */
uint32_t
ble_ll_rand(void)
{
static unsigned short xsubi[3];
static bool init = true;
if (init) {
init = false;
ble_ll_rand_data_get((uint8_t *)xsubi, sizeof(xsubi));
}
return (uint32_t) jrand48(xsubi);
}
/**
* Called to obtain a "prand" as defined in core V4.2 Vol 6 Part B 1.3.2.2
*

View File

@@ -295,7 +295,7 @@ ble_ll_scan_req_backoff(struct ble_ll_scan_sm *scansm, int success)
STATS_INC(ble_ll_stats, scan_req_txf);
}
scansm->backoff_count = rand() & (scansm->upper_limit - 1);
scansm->backoff_count = ble_ll_rand() & (scansm->upper_limit - 1);
++scansm->backoff_count;
BLE_LL_ASSERT(scansm->backoff_count <= 256);
}
@@ -307,7 +307,7 @@ ble_ll_scan_refresh_nrpa(struct ble_ll_scan_sm *scansm)
ble_npl_time_t now;
now = ble_npl_time_get();
if ((ble_npl_stime_t)(now - scansm->scan_nrpa_timer) >= 0) {
if (CPUTIME_GEQ(now, scansm->scan_nrpa_timer)) {
/* Generate new NRPA */
ble_ll_rand_data_get(scansm->scan_nrpa, BLE_DEV_ADDR_LEN);
scansm->scan_nrpa[5] &= ~0xc0;
@@ -619,7 +619,7 @@ ble_ll_scan_add_scan_rsp_adv(uint8_t *addr, uint8_t txadd,
static int
ble_ll_hci_send_legacy_ext_adv_report(uint8_t evtype,
const uint8_t *addr, uint8_t addr_type,
uint8_t rssi,
int8_t rssi,
uint8_t adv_data_len,
struct os_mbuf *adv_data,
const uint8_t *inita, uint8_t inita_type)
@@ -1127,6 +1127,22 @@ ble_ll_scan_sm_stop(int chk_disable)
scansm = &g_ble_ll_scan_sm;
os_cputime_timer_stop(&scansm->scan_timer);
/* Only set state if we are currently in a scan window */
if (chk_disable) {
OS_ENTER_CRITICAL(sr);
lls = ble_ll_state_get();
if ((lls == BLE_LL_STATE_SCANNING) ||
(lls == BLE_LL_STATE_INITIATING && chk_disable == 1)) {
/* Disable phy */
ble_phy_disable();
/* Set LL state to standby */
ble_ll_state_set(BLE_LL_STATE_STANDBY);
}
OS_EXIT_CRITICAL(sr);
}
OS_ENTER_CRITICAL(sr);
/* Disable scanning state machine */
@@ -1151,22 +1167,6 @@ ble_ll_scan_sm_stop(int chk_disable)
/* Count # of times stopped */
STATS_INC(ble_ll_stats, scan_stops);
/* Only set state if we are currently in a scan window */
if (chk_disable) {
OS_ENTER_CRITICAL(sr);
lls = ble_ll_state_get();
if ((lls == BLE_LL_STATE_SCANNING) ||
(lls == BLE_LL_STATE_INITIATING && chk_disable == 1)) {
/* Disable phy */
ble_phy_disable();
/* Set LL state to standby */
ble_ll_state_set(BLE_LL_STATE_STANDBY);
}
OS_EXIT_CRITICAL(sr);
}
/* No need for RF anymore */
OS_ENTER_CRITICAL(sr);
ble_ll_rfmgmt_scan_changed(false, 0);
@@ -1993,10 +1993,10 @@ ble_ll_scan_rx_filter(struct ble_mbuf_hdr *hdr, struct ble_ll_scan_addr_data *ad
{
struct ble_ll_scan_sm *scansm = &g_ble_ll_scan_sm;
struct ble_ll_scan_params *scanp = scansm->scanp;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
struct ble_ll_aux_data *aux_data = hdr->rxinfo.user_data;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
struct ble_mbuf_hdr_rxinfo *rxinfo = &hdr->rxinfo;
struct ble_ll_resolv_entry *rl = NULL;
#endif
@@ -2229,6 +2229,7 @@ ble_ll_scan_rx_isr_on_aux(uint8_t pdu_type, uint8_t *rxbuf,
*/
if (aux_data->flags & BLE_LL_AUX_IS_MATCHED) {
rxinfo->flags |= BLE_MBUF_HDR_F_DEVMATCH;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
rxinfo->rpa_index = aux_data->rpa_index;
if (rxinfo->rpa_index >= 0) {
rxinfo->flags |= BLE_MBUF_HDR_F_RESOLVED;
@@ -2236,6 +2237,7 @@ ble_ll_scan_rx_isr_on_aux(uint8_t pdu_type, uint8_t *rxbuf,
if (aux_data->flags & BLE_LL_AUX_IS_TARGETA_RESOLVED) {
rxinfo->flags |= BLE_MBUF_HDR_F_TARGETA_RESOLVED;
}
#endif
goto done;
}
@@ -2687,10 +2689,16 @@ ble_ll_hci_send_ext_adv_report(uint8_t ptype, uint8_t *adva, uint8_t adva_type,
/*
* We need another event if either there are still some data left to
* send in current PDU or scan is not completed. The only exception is
* when this is a scannable event which is not a scan response.
* send in current PDU or scan is not completed. There are two exceptions
* though:
* - we sent all data from this PDU and there is scan error set already;
* it may be set before entering current function due to failed aux
* scan scheduling
* - this is a scannable event which is not a scan response
*/
need_event = ((offset < datalen) || (aux_data && !(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_COMPLETE))) && !is_scannable_aux;
need_event = ((offset < datalen) || (aux_data && !(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_COMPLETE))) &&
!((offset == datalen) && (aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR)) &&
!is_scannable_aux;
if (need_event) {
/*
@@ -3021,7 +3029,8 @@ ble_ll_scan_rx_pkt_in_on_legacy(uint8_t pdu_type, struct os_mbuf *om,
if (!BLE_MBUF_HDR_DEVMATCH(hdr) ||
!BLE_MBUF_HDR_CRC_OK(hdr) ||
BLE_MBUF_HDR_IGNORED(hdr)) {
BLE_MBUF_HDR_IGNORED(hdr) ||
!scansm->scan_enabled) {
return;
}
@@ -3060,10 +3069,6 @@ ble_ll_scan_rx_pkt_in_on_aux(uint8_t pdu_type, struct os_mbuf *om,
bool send_hci_report;
int rc;
if (!scansm->ext_scanning) {
goto scan_continue;
}
if (aux_data) {
aux_data->flags_ll |= aux_data->flags_isr;
}
@@ -3079,7 +3084,8 @@ ble_ll_scan_rx_pkt_in_on_aux(uint8_t pdu_type, struct os_mbuf *om,
BLE_MBUF_HDR_IGNORED(hdr) ||
BLE_MBUF_HDR_AUX_INVALID(hdr) ||
(aux_data->flags_ll & BLE_LL_AUX_FLAG_SCAN_ERROR) ||
(pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND)) {
(pdu_type != BLE_ADV_PDU_TYPE_ADV_EXT_IND) ||
!scansm->scan_enabled) {
if (aux_data) {
ble_ll_scan_end_adv_evt(aux_data);
ble_ll_scan_aux_data_unref(aux_data);

View File

@@ -91,14 +91,14 @@ ble_ll_sched_is_overlap(struct ble_ll_sched_item *s1,
int rc;
rc = 1;
if ((int32_t)(s1->start_time - s2->start_time) < 0) {
if (CPUTIME_LT(s1->start_time, s2->start_time)) {
/* Make sure this event does not overlap current event */
if ((int32_t)(s1->end_time - s2->start_time) <= 0) {
if (CPUTIME_LEQ(s1->end_time, s2->start_time)) {
rc = 0;
}
} else {
/* Check for overlap */
if ((int32_t)(s1->start_time - s2->end_time) >= 0) {
if (CPUTIME_GEQ(s1->start_time, s2->end_time)) {
rc = 0;
}
}
@@ -119,7 +119,7 @@ ble_ll_sched_overlaps_current(struct ble_ll_sched_item *sch)
rc = 0;
if (ble_ll_state_get() == BLE_LL_STATE_CONNECTION) {
ce_end_time = ble_ll_conn_get_ce_end_time();
if ((int32_t)(ce_end_time - sch->start_time) > 0) {
if (CPUTIME_GT(ce_end_time, sch->start_time)) {
rc = 1;
}
}
@@ -186,7 +186,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
sch->end_time = connsm->ce_end_time;
/* Better be past current time or we just leave */
if ((int32_t)(sch->start_time - os_cputime_get32()) < 0) {
if (CPUTIME_LT(sch->start_time, os_cputime_get32())) {
return -1;
}
@@ -224,7 +224,7 @@ ble_ll_sched_conn_reschedule(struct ble_ll_conn_sm *connsm)
end_overlap = entry;
}
} else {
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
rc = 0;
TAILQ_INSERT_BEFORE(entry, sch, link);
break;
@@ -476,7 +476,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
sch->end_time = earliest_end;
/* We can insert if before entry in list */
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
if ((earliest_start - initial_start) <= itvl_t) {
rc = 0;
TAILQ_INSERT_BEFORE(entry, sch, link);
@@ -663,7 +663,7 @@ ble_ll_sched_master_new(struct ble_ll_conn_sm *connsm,
sch->end_time = earliest_end;
/* We can insert if before entry in list */
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
if ((earliest_start - initial_start) <= itvl_t) {
rc = 0;
TAILQ_INSERT_BEFORE(entry, sch, link);
@@ -778,7 +778,7 @@ ble_ll_sched_slave_new(struct ble_ll_conn_sm *connsm)
while (1) {
next_sch = entry->link.tqe_next;
/* Insert if event ends before next starts */
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
rc = 0;
TAILQ_INSERT_BEFORE(entry, sch, link);
break;
@@ -1055,7 +1055,7 @@ ble_ll_sched_adv_new(struct ble_ll_sched_item *sch, ble_ll_sched_adv_new_cb cb,
os_cputime_timer_stop(&g_ble_ll_sched_timer);
TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
/* We can insert if before entry in list */
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
TAILQ_INSERT_BEFORE(entry, sch, link);
break;
}
@@ -1119,7 +1119,7 @@ ble_ll_sched_periodic_adv(struct ble_ll_sched_item *sch, uint32_t *start,
os_cputime_timer_stop(&g_ble_ll_sched_timer);
TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
/* We can insert if before entry in list */
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
TAILQ_INSERT_BEFORE(entry, sch, link);
break;
}
@@ -1208,7 +1208,7 @@ ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start,
end_overlap = entry;
}
} else {
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
before = entry;
break;
}
@@ -1241,7 +1241,7 @@ ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start,
sch->end_time = sch->start_time + duration;
while (1) {
next_sch = entry->link.tqe_next;
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
rand_ticks = entry->start_time - sch->end_time;
before = entry;
TAILQ_INSERT_BEFORE(before, sch, link);
@@ -1274,7 +1274,7 @@ ble_ll_sched_adv_reschedule(struct ble_ll_sched_item *sch, uint32_t *start,
if (!rc) {
sch->enqueued = 1;
if (rand_ticks) {
sch->start_time += rand() % rand_ticks;
sch->start_time += ble_ll_rand() % rand_ticks;
}
sch->end_time = sch->start_time + duration;
*start = sch->start_time;
@@ -1588,7 +1588,7 @@ ble_ll_sched_scan_req_over_aux_ptr(uint32_t chan, uint8_t phy_mode)
while (sch) {
/* Let's check if there is no scheduled item which want to start within
* given usecs.*/
if ((int32_t)(sch->start_time - now + os_cputime_usecs_to_ticks(usec_dur)) > 0) {
if (CPUTIME_GT(sch->start_time, now + os_cputime_usecs_to_ticks(usec_dur))) {
/* We are fine. Have time for scan req */
return 0;
}
@@ -1678,7 +1678,7 @@ ble_ll_sched_aux_scan(struct ble_mbuf_hdr *ble_hdr,
os_cputime_timer_stop(&g_ble_ll_sched_timer);
TAILQ_FOREACH(entry, &g_ble_ll_sched_q, link) {
/* We can insert if before entry in list */
if ((int32_t)(sch->end_time - entry->start_time) <= 0) {
if (CPUTIME_LEQ(sch->end_time, entry->start_time)) {
rc = 0;
TAILQ_INSERT_BEFORE(entry, sch, link);
sch->enqueued = 1;

View File

@@ -37,7 +37,22 @@
/* Octet 10 */
#define BLE_SUPP_CMD_RD_TX_PWR (0 << 2)
#define BLE_LL_SUPP_CMD_OCTET_10 (BLE_SUPP_CMD_RD_TX_PWR)
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_CTRL_TO_HOST_FLOW_CONTROL)
#define BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW (1 << 5)
#define BLE_SUPP_CMD_HOST_BUFFER_SIZE (1 << 6)
#define BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS (1 << 7)
#else
#define BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW (0 << 5)
#define BLE_SUPP_CMD_HOST_BUFFER_SIZE (0 << 6)
#define BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_10 \
( \
BLE_SUPP_CMD_RD_TX_PWR | \
BLE_SUPP_CMD_SET_CTRL_TO_HOST_FLOW | \
BLE_SUPP_CMD_HOST_BUFFER_SIZE | \
BLE_SUPP_CMD_HOST_NUM_COMP_PACKETS \
)
/* Octet 14 */
#define BLE_SUPP_CMD_RD_LOC_VER (1 << 3)
@@ -405,10 +420,77 @@
#define BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS (0 << 0)
#define BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS (0 << 1)
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
#define BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 (1 << 5)
#define BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC (1 << 6)
#define BLE_SUPP_CMD_LE_SET_CIG_PARAM (1 << 7)
#else
#define BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 (0 << 5)
#define BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC (0 << 6)
#define BLE_SUPP_CMD_LE_SET_CIG_PARAM (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_41 \
( \
BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS | \
BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS \
BLE_SUPP_CMD_LE_PADV_SYNC_TRANSFER_PARAMS | \
BLE_SUPP_CMD_LE_PADV_DEFAULT_SYNC_TRANSFER_PARAMS | \
BLE_SUPP_CMD_LE_READ_BUF_SIZE_V2 | \
BLE_SUPP_CMD_LE_READ_ISO_TX_SYNC | \
BLE_SUPP_CMD_LE_SET_CIG_PARAM \
)
/* Octet 42 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_ISO)
#define BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST (1 << 0)
#define BLE_SUPP_CMD_LE_CREATE_CIS (1 << 1)
#define BLE_SUPP_CMD_LE_REMOVE_CIG (1 << 2)
#define BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ (1 << 3)
#define BLE_SUPP_CMD_LE_REJECT_CIS_REQ (1 << 4)
#define BLE_SUPP_CMD_LE_CREATE_BIG (1 << 5)
#define BLE_SUPP_CMD_LE_CREATE_BIG_TEST (1 << 6)
#define BLE_SUPP_CMD_LE_TERMINATE_BIG (1 << 7)
#else
#define BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST (0 << 0)
#define BLE_SUPP_CMD_LE_CREATE_CIS (0 << 1)
#define BLE_SUPP_CMD_LE_REMOVE_CIG (0 << 2)
#define BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ (0 << 3)
#define BLE_SUPP_CMD_LE_REJECT_CIS_REQ (0 << 4)
#define BLE_SUPP_CMD_LE_CREATE_BIG (0 << 5)
#define BLE_SUPP_CMD_LE_CREATE_BIG_TEST (0 << 6)
#define BLE_SUPP_CMD_LE_TERMINATE_BIG (0 << 7)
#endif
#define BLE_LL_SUPP_CMD_OCTET_42 \
( \
BLE_SUPP_CMD_LE_SET_CIG_PARAM_TEST | \
BLE_SUPP_CMD_LE_CREATE_CIS | \
BLE_SUPP_CMD_LE_REMOVE_CIG | \
BLE_SUPP_CMD_LE_ACCEPT_CIS_REQ | \
BLE_SUPP_CMD_LE_REJECT_CIS_REQ | \
BLE_SUPP_CMD_LE_CREATE_BIG | \
BLE_SUPP_CMD_LE_CREATE_BIG_TEST | \
BLE_SUPP_CMD_LE_TERMINATE_BIG \
)
/* Octet 43 */
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_SCA_UPDATE)
#define BLE_SUPP_CMD_LE_REQUEST_PEER_SCA (1 << 2)
#else
#define BLE_SUPP_CMD_LE_REQUEST_PEER_SCA (0 << 0)
#endif
#define BLE_LL_SUPP_CMD_OCTET_43 \
( \
BLE_SUPP_CMD_LE_REQUEST_PEER_SCA \
)
/* Octet 44 */
#if MYNEWT_VAL(BLE_VERSION) >= 52
#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (1 << 0)
#else
#define BLE_SUPP_CMD_LE_SET_HOST_FEATURE (0 << 0)
#endif
#define BLE_LL_SUPP_CMD_OCTET_44 \
( \
BLE_SUPP_CMD_LE_SET_HOST_FEATURE \
)
/* Defines the array of supported commands */
@@ -456,6 +538,9 @@ const uint8_t g_ble_ll_supp_cmds[BLE_LL_SUPP_CMD_LEN] =
BLE_LL_SUPP_CMD_OCTET_39,
BLE_LL_SUPP_CMD_OCTET_40, /* Octet 40 */
BLE_LL_SUPP_CMD_OCTET_41,
BLE_LL_SUPP_CMD_OCTET_42,
BLE_LL_SUPP_CMD_OCTET_43,
BLE_LL_SUPP_CMD_OCTET_44,
};
#endif

View File

@@ -61,6 +61,7 @@
#define BLE_LL_SYNC_SM_FLAG_DISABLED 0x0040
#define BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED 0x0080
#define BLE_LL_SYNC_SM_FLAG_HCI_TRUNCATED 0x0100
#define BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP 0x0200
#define BLE_LL_SYNC_CHMAP_LEN 5
#define BLE_LL_SYNC_ITVL_USECS 1250
@@ -76,6 +77,9 @@ struct ble_ll_sync_sm {
uint8_t chanmap[BLE_LL_SYNC_CHMAP_LEN];
uint8_t num_used_chans;
uint8_t chanmap_new[BLE_LL_SYNC_CHMAP_LEN];
uint16_t chanmap_new_instant;
uint8_t chan_index;
uint8_t chan_chain;
@@ -526,7 +530,8 @@ ble_ll_sync_rx_isr_start(uint8_t pdu_type, struct ble_mbuf_hdr *rxhdr)
}
static int
ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power)
ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power,
uint8_t **acad, uint8_t *acad_len)
{
uint8_t *rxbuf = om->om_data;
uint8_t ext_hdr_flags;
@@ -586,12 +591,17 @@ ble_ll_sync_parse_ext_hdr(struct os_mbuf *om, uint8_t **aux, int8_t *tx_power)
i += BLE_LL_EXT_ADV_TX_POWER_SIZE;
}
/* TODO Handle ACAD if needed */
/* sanity check */
if (i > ext_hdr_len) {
return -1;
}
/* ACAD */
if (ext_hdr_len > (i + 1)) {
*acad = ext_hdr + i;
*acad_len = ext_hdr_len - i - 1;
}
}
return pdu_len - ext_hdr_len - 1;
@@ -997,6 +1007,70 @@ ble_ll_sync_check_failed(struct ble_ll_sync_sm *sm)
ble_ll_sync_est_event_failed(BLE_ERR_CONN_ESTABLISHMENT);
}
static bool
ble_ll_sync_check_acad(struct ble_ll_sync_sm *sm,
const uint8_t *acad, uint8_t acad_len)
{
const struct ble_ll_acad_channel_map_update_ind *chmu;
unsigned int ad_len;
uint8_t ad_type;
/* assume no empty fields */
while (acad_len > 2) {
ad_len = acad[0];
ad_type = acad[1];
/* early termination should not happen in ACAD */
if (ad_len == 0) {
return false;
}
/* check if not passing pass acad data */
if (ad_len + 1 > acad_len) {
return false;
}
switch (ad_type) {
case BLE_LL_ACAD_CHANNEL_MAP_UPDATE_IND:
chmu = (const void *)&acad[2];
if (ad_len - 1 != sizeof(*chmu)) {
return false;
}
/* Channels Mask (37 bits)
* TODO should we check this?
*/
sm->chanmap_new[0] = chmu->map[0];
sm->chanmap_new[1] = chmu->map[1];
sm->chanmap_new[2] = chmu->map[2];
sm->chanmap_new[3] = chmu->map[3];
sm->chanmap_new[4] = chmu->map[4] & 0x1f;
/* drop if channel map is invalid */
if (ble_ll_utils_calc_num_used_chans(sm->chanmap_new) == 0) {
return false;
}
sm->chanmap_new_instant = le16toh(chmu->instant);
sm->flags |= BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP;
break;
default:
break;
}
acad += ad_len + 1;
acad_len -= ad_len + 1;
}
/* should have no trailing zeros */
if (acad_len) {
return false;
}
return true;
}
void
ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
{
@@ -1004,7 +1078,10 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
bool aux_scheduled = false;
int8_t tx_power = 127; /* defaults to not available */
uint8_t *aux = NULL;
uint8_t *acad = NULL;
uint8_t acad_len;
int datalen;
bool reports_enabled;
BLE_LL_ASSERT(sm);
@@ -1049,36 +1126,43 @@ ble_ll_sync_rx_pkt_in(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr)
goto end_event;
}
if (ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) &&
!(sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED)) {
/* get ext header data */
datalen = ble_ll_sync_parse_ext_hdr(rxpdu, &aux, &tx_power);
if (datalen < 0) {
/* we got bad packet, end event */
goto end_event;
}
/* get ext header data */
datalen = ble_ll_sync_parse_ext_hdr(rxpdu, &aux, &tx_power, &acad, &acad_len);
if (datalen < 0) {
/* we got bad packet, end event */
goto end_event;
}
reports_enabled = ble_ll_hci_is_le_event_enabled(BLE_HCI_LE_SUBEV_PERIODIC_ADV_RPT) &&
!(sm->flags & BLE_LL_SYNC_SM_FLAG_DISABLED);
/* no need to schedule for chain if reporting is disabled */
if (reports_enabled) {
/* if aux is present, we need to schedule ASAP */
if (aux && (ble_ll_sync_schedule_chain(sm, hdr, aux) == 0)) {
aux_scheduled = true;
}
}
/* in case data reporting is enabled we need to send sync established here */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
ble_ll_sync_established(sm);
}
/* check ACAD, needs to be done before rxpdu is adjusted for ADV data */
if (acad && !ble_ll_sync_check_acad(sm, acad, acad_len)) {
/* we got bad packet (bad ACAD data), end event */
goto end_event;
}
/* we need to establish link even if reporting was disabled */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
ble_ll_sync_established(sm);
}
/* only if reporting is enabled */
if (reports_enabled) {
/* Adjust rxpdu to contain advertising data only */
ble_ll_sync_adjust_ext_hdr(rxpdu);
/* send reports from this PDU */
ble_ll_sync_send_per_adv_rpt(sm, rxpdu, hdr->rxinfo.rssi, tx_power,
datalen, aux, aux_scheduled);
} else {
/* we need to establish link even if reporting was disabled */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_ESTABLISHING) {
ble_ll_sync_established(sm);
}
}
/* if chain was scheduled we don't end event yet */
@@ -1132,6 +1216,20 @@ ble_ll_sync_next_event(struct ble_ll_sync_sm *sm, uint32_t cur_ww_adjust)
/* Set event counter to the next event */
sm->event_cntr += 1 + skip;
/* update channel map if needed */
if (sm->flags & BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP) {
if (((int16_t)(sm->event_cntr - sm->chanmap_new_instant)) >= 0) {
/* map was verified on reception */
sm->chanmap[0] = sm->chanmap_new[0];
sm->chanmap[1] = sm->chanmap_new[1];
sm->chanmap[2] = sm->chanmap_new[2];
sm->chanmap[3] = sm->chanmap_new[3];
sm->chanmap[4] = sm->chanmap_new[4];
sm->num_used_chans = ble_ll_utils_calc_num_used_chans(sm->chanmap);
sm->flags &= ~BLE_LL_SYNC_SM_FLAG_NEW_CHANMAP;
}
}
/* Calculate channel index of next event */
sm->chan_index = ble_ll_utils_calc_dci_csa2(sm->event_cntr, sm->channel_id,
sm->num_used_chans, sm->chanmap);
@@ -2092,10 +2190,10 @@ ble_ll_sync_send_sync_ind(struct ble_ll_sync_sm *syncsm,
if (syncsm->flags & BLE_LL_SYNC_SM_FLAG_ADDR_RESOLVED) {
sync_ind[24] |= 1 << 4;
} else {
sync_ind[24] |= (syncsm->adv_addr_type == BLE_ADDR_RANDOM) << 4 ;
sync_ind[24] |= (syncsm->adv_addr_type == BLE_ADDR_RANDOM) << 4;
}
sync_ind[24] |= MYNEWT_VAL(BLE_LL_MASTER_SCA) << 5;
sync_ind[24] |= BLE_LL_SCA_ENUM << 5;
/* PHY */
sync_ind[25] = (0x01 << (ble_ll_sync_phy_mode_to_hci(syncsm->phy_mode) - 1));

View File

@@ -51,8 +51,8 @@ ble_ll_utils_calc_access_addr(void)
aa = 0;
while (1) {
/* Get two, 16-bit random numbers */
aa_low = rand() & 0xFFFF;
aa_high = rand() & 0xFFFF;
aa_low = ble_ll_rand() & 0xFFFF;
aa_high = ble_ll_rand() & 0xFFFF;
/* All four bytes cannot be equal */
if (aa_low == aa_high) {
@@ -293,8 +293,7 @@ ble_ll_utils_calc_window_widening(uint32_t anchor_point,
time_since_last_anchor = (int32_t)(anchor_point - last_anchor_point);
if (time_since_last_anchor > 0) {
delta_msec = os_cputime_ticks_to_usecs(time_since_last_anchor) / 1000;
total_sca_ppm = g_ble_sca_ppm_tbl[master_sca] +
MYNEWT_VAL(BLE_LL_OUR_SCA);
total_sca_ppm = g_ble_sca_ppm_tbl[master_sca] + MYNEWT_VAL(BLE_LL_SCA);
window_widening = (total_sca_ppm * delta_msec) / 1000;
}

View File

@@ -39,41 +39,47 @@ extern "C" {
struct hci_le_conn_complete;
struct hci_conn_update;
#define BLE_GAP_ADV_ITVL_MS(t) ((t) * 1000 / BLE_HCI_ADV_ITVL)
#define BLE_GAP_SCAN_ITVL_MS(t) ((t) * 1000 / BLE_HCI_SCAN_ITVL)
#define BLE_GAP_SCAN_WIN_MS(t) ((t) * 1000 / BLE_HCI_SCAN_ITVL)
#define BLE_GAP_CONN_ITVL_MS(t) ((t) * 1000 / BLE_HCI_CONN_ITVL)
#define BLE_GAP_SUPERVISION_TIMEOUT_MS(t) ((t) / 10)
/** 30 ms. */
#define BLE_GAP_ADV_FAST_INTERVAL1_MIN (30 * 1000 / BLE_HCI_ADV_ITVL)
#define BLE_GAP_ADV_FAST_INTERVAL1_MIN BLE_GAP_ADV_ITVL_MS(30)
/** 60 ms. */
#define BLE_GAP_ADV_FAST_INTERVAL1_MAX (60 * 1000 / BLE_HCI_ADV_ITVL)
#define BLE_GAP_ADV_FAST_INTERVAL1_MAX BLE_GAP_ADV_ITVL_MS(60)
/** 100 ms. */
#define BLE_GAP_ADV_FAST_INTERVAL2_MIN (100 * 1000 / BLE_HCI_ADV_ITVL)
#define BLE_GAP_ADV_FAST_INTERVAL2_MIN BLE_GAP_ADV_ITVL_MS(100)
/** 150 ms. */
#define BLE_GAP_ADV_FAST_INTERVAL2_MAX (150 * 1000 / BLE_HCI_ADV_ITVL)
#define BLE_GAP_ADV_FAST_INTERVAL2_MAX BLE_GAP_ADV_ITVL_MS(150)
/** 30 ms; active scanning. */
#define BLE_GAP_SCAN_FAST_INTERVAL_MIN (30 * 1000 / BLE_HCI_ADV_ITVL)
#define BLE_GAP_SCAN_FAST_INTERVAL_MIN BLE_GAP_SCAN_ITVL_MS(30)
/** 60 ms; active scanning. */
#define BLE_GAP_SCAN_FAST_INTERVAL_MAX (60 * 1000 / BLE_HCI_ADV_ITVL)
#define BLE_GAP_SCAN_FAST_INTERVAL_MAX BLE_GAP_SCAN_ITVL_MS(60)
/** 11.25 ms; limited discovery interval. */
#define BLE_GAP_LIM_DISC_SCAN_INT (11.25 * 1000 / BLE_HCI_SCAN_ITVL)
#define BLE_GAP_LIM_DISC_SCAN_INT BLE_GAP_SCAN_ITVL_MS(11.25)
/** 11.25 ms; limited discovery window (not from the spec). */
#define BLE_GAP_LIM_DISC_SCAN_WINDOW (11.25 * 1000 / BLE_HCI_SCAN_ITVL)
#define BLE_GAP_LIM_DISC_SCAN_WINDOW BLE_GAP_SCAN_WIN_MS(11.25)
/** 30 ms; active scanning. */
#define BLE_GAP_SCAN_FAST_WINDOW (30 * 1000 / BLE_HCI_SCAN_ITVL)
#define BLE_GAP_SCAN_FAST_WINDOW BLE_GAP_SCAN_WIN_MS(30)
/* 30.72 seconds; active scanning. */
#define BLE_GAP_SCAN_FAST_PERIOD (30.72 * 1000)
#define BLE_GAP_SCAN_FAST_PERIOD BLE_GAP_SCAN_ITVL_MS(30.72)
/** 1.28 seconds; background scanning. */
#define BLE_GAP_SCAN_SLOW_INTERVAL1 (1280 * 1000 / BLE_HCI_SCAN_ITVL)
#define BLE_GAP_SCAN_SLOW_INTERVAL1 BLE_GAP_SCAN_ITVL_MS(1280)
/** 11.25 ms; background scanning. */
#define BLE_GAP_SCAN_SLOW_WINDOW1 (11.25 * 1000 / BLE_HCI_SCAN_ITVL)
#define BLE_GAP_SCAN_SLOW_WINDOW1 BLE_GAP_SCAN_WIN_MS(11.25)
/** 10.24 seconds. */
#define BLE_GAP_DISC_DUR_DFLT (10.24 * 1000)
@@ -88,10 +94,10 @@ struct hci_conn_update;
#define BLE_GAP_CONN_PAUSE_PERIPHERAL (5 * 1000)
/* 30 ms. */
#define BLE_GAP_INITIAL_CONN_ITVL_MIN (30 * 1000 / BLE_HCI_CONN_ITVL)
#define BLE_GAP_INITIAL_CONN_ITVL_MIN BLE_GAP_CONN_ITVL_MS(30)
/* 50 ms. */
#define BLE_GAP_INITIAL_CONN_ITVL_MAX (50 * 1000 / BLE_HCI_CONN_ITVL)
#define BLE_GAP_INITIAL_CONN_ITVL_MAX BLE_GAP_CONN_ITVL_MS(50)
/** Default channels mask: all three channels are used. */
#define BLE_GAP_ADV_DFLT_CHANNEL_MAP 0x07

View File

@@ -21,6 +21,7 @@
#define H_BLE_HS_LOG_
#include "nimble/porting/nimble/include/modlog/modlog.h"
#include "nimble/porting/nimble/include/log/log.h"
/* Only include the logcfg header if this version of newt can generate it. */
#if MYNEWT_VAL(NEWT_FEATURE_LOGCFG)

View File

@@ -32,6 +32,7 @@ extern "C" {
int ble_monitor_log(int level, const char *fmt, ...);
int ble_monitor_out(int c);
void ble_monitor_deinit(void);
#ifdef __cplusplus
}

View File

@@ -28,14 +28,23 @@ extern "C" {
#define BT_MESH_ADDR_RELAYS 0xfffe
#define BT_MESH_KEY_UNUSED 0xffff
#define BT_MESH_KEY_ANY 0xffff
#define BT_MESH_KEY_DEV 0xfffe
#define BT_MESH_KEY_DEV_LOCAL BT_MESH_KEY_DEV
#define BT_MESH_KEY_DEV_REMOTE 0xfffd
#define BT_MESH_KEY_DEV_ANY 0xfffc
#define BT_MESH_ADDR_IS_UNICAST(addr) ((addr) && (addr) < 0x8000)
#define BT_MESH_ADDR_IS_GROUP(addr) ((addr) >= 0xc000 && (addr) <= 0xff00)
#define BT_MESH_ADDR_IS_VIRTUAL(addr) ((addr) >= 0x8000 && (addr) < 0xc000)
#define BT_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfffb)
#define BT_MESH_IS_DEV_KEY(key) (key == BT_MESH_KEY_DEV_LOCAL || \
key == BT_MESH_KEY_DEV_REMOTE)
#define BT_MESH_APP_SEG_SDU_MAX 12
#define BT_MESH_TX_SDU_MAX (CONFIG_BT_MESH_TX_SEG_MAX * BT_MESH_APP_SEG_SDU_MAX)
#define BT_MESH_RX_SDU_MAX (CONFIG_BT_MESH_RX_SEG_MAX * BT_MESH_APP_SEG_SDU_MAX)
/** Helper to define a mesh element within an array.
*
* In case the element has no SIG or Vendor models the helper
@@ -57,13 +66,13 @@ extern "C" {
/** Abstraction that describes a Mesh Element */
struct bt_mesh_elem {
/* Unicast Address. Set at runtime during provisioning. */
u16_t addr;
uint16_t addr;
/* Location Descriptor (GATT Bluetooth Namespace Descriptors) */
const u16_t loc;
const uint16_t loc;
const u8_t model_count;
const u8_t vnd_model_count;
const uint8_t model_count;
const uint8_t vnd_model_count;
struct bt_mesh_model * const models;
struct bt_mesh_model * const vnd_models;
@@ -132,33 +141,33 @@ struct bt_mesh_elem {
/** Message sending context. */
struct bt_mesh_msg_ctx {
/** NetKey Index of the subnet to send the message on. */
u16_t net_idx;
uint16_t net_idx;
/** AppKey Index to encrypt the message with. */
u16_t app_idx;
uint16_t app_idx;
/** Remote address. */
u16_t addr;
uint16_t addr;
/** Destination address of a received message. Not used for sending. */
u16_t recv_dst;
uint16_t recv_dst;
/** RSSI of received packet. Not used for sending. */
s8_t recv_rssi;
int8_t recv_rssi;
/** Received TTL value. Not used for sending. */
u8_t recv_ttl;
uint8_t recv_ttl;
/** Force sending reliably by using segment acknowledgement */
bool send_rel;
/** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */
u8_t send_ttl;
uint8_t send_ttl;
};
struct bt_mesh_model_op {
/* OpCode encoded using the BT_MESH_MODEL_OP_* macros */
const u32_t opcode;
const uint32_t opcode;
/* Minimum required message length */
const size_t min_len;
@@ -324,7 +333,7 @@ struct bt_mesh_model_op {
*
* @return Transmission count (actual transmissions is N + 1).
*/
#define BT_MESH_TRANSMIT_COUNT(transmit) (((transmit) & (u8_t)BIT_MASK(3)))
#define BT_MESH_TRANSMIT_COUNT(transmit) (((transmit) & (uint8_t)BIT_MASK(3)))
/** @def BT_MESH_TRANSMIT_INT
*
@@ -375,23 +384,24 @@ struct bt_mesh_model_pub {
/** The model the context belongs to. Initialized by the stack. */
struct bt_mesh_model *mod;
u16_t addr; /**< Publish Address. */
u16_t key; /**< Publish AppKey Index. */
uint16_t addr; /**< Publish Address. */
uint16_t key; /**< Publish AppKey Index. */
u8_t ttl; /**< Publish Time to Live. */
u8_t retransmit; /**< Retransmit Count & Interval Steps. */
u8_t period; /**< Publish Period. */
u8_t period_div:4, /**< Divisor for the Period. */
uint8_t ttl; /**< Publish Time to Live. */
uint8_t retransmit; /**< Retransmit Count & Interval Steps. */
uint8_t period; /**< Publish Period. */
uint8_t period_div:4, /**< Divisor for the Period. */
cred:1, /**< Friendship Credentials Flag. */
send_rel:1,
fast_period:1,/**< Use FastPeriodDivisor */
count:3; /**< Retransmissions left. */
u32_t period_start; /**< Start of the current period. */
uint32_t period_start; /**< Start of the current period. */
/** @brief Publication buffer, containing the publication message.
*
* The application is expected to initialize this with
* a valid net_buf_simple pointer, with the help of e.g.
* a valid os_mbuf pointer, with the help of e.g.
* the NET_BUF_SIMPLE() macro. The publication buffer must
* contain a valid publication message before calling the
* bt_mesh_model_publish() API or after the publication's
@@ -414,6 +424,10 @@ struct bt_mesh_model_pub {
* will be called periodically and is expected to update
* @ref bt_mesh_model_pub.msg with a valid publication
* message.
*
* If the callback returns non-zero, the publication is skipped
* and will resume on the next periodic publishing interval.
*
*
* @param mod The Model the Publication Context belogs to.
*
@@ -432,16 +446,18 @@ struct bt_mesh_model_cb {
* @sa settings_handler::h_set
*
* @param model Model to set the persistent data of.
* @param name Name/key of the settings item.
* @param val Data from the backend.
*
* @return 0 on success, error otherwise.
*/
int (*const settings_set)(struct bt_mesh_model *model, char *val);
int (*const settings_set)(struct bt_mesh_model *model,
const char *name, char *val);
/** @brief Callback called when all settings have been loaded.
/** @brief Callback called when the mesh is started.
*
* This handler gets called after the settings have been loaded in
* full.
* This handler gets called after the node has been provisioned, or
* after all mesh data has been loaded from persistent storage.
*
* @sa settings_handler::h_commit
*
@@ -449,12 +465,17 @@ struct bt_mesh_model_cb {
*
* @return 0 on success, error otherwise.
*/
int (*const settings_commit)(struct bt_mesh_model *model);
int (*const start)(struct bt_mesh_model *model);
/** @brief Model init callback.
*
* Called on every model instance during mesh initialization.
*
*
* If any of the model init callbacks return an error, the Mesh
* subsystem initialization will be aborted, and the error will be
* returned to the caller of @ref bt_mesh_init.
*
* @param model Model to be initialized.
*
* @return 0 on success, error otherwise.
@@ -466,6 +487,9 @@ struct bt_mesh_model_cb {
* Called when the mesh node is reset. All model data is deleted on
* reset, and the model should clear its state.
*
* @note If the model stores any persistent data, this needs to be
* erased manually.
*
* @param model Model this callback belongs to.
*/
void (*const reset)(struct bt_mesh_model *model);
@@ -474,26 +498,26 @@ struct bt_mesh_model_cb {
/** Abstraction that describes a Mesh Model instance */
struct bt_mesh_model {
union {
const u16_t id;
const uint16_t id;
struct {
u16_t company;
u16_t id;
uint16_t company;
uint16_t id;
} vnd;
};
/* Internal information, mainly for persistent storage */
u8_t elem_idx; /* Belongs to Nth element */
u8_t mod_idx; /* Is the Nth model in the element */
u16_t flags; /* Model flags for internal bookkeeping */
uint8_t elem_idx; /* Belongs to Nth element */
uint8_t mod_idx; /* Is the Nth model in the element */
uint16_t flags; /* Model flags for internal bookkeeping */
/* Model Publication */
struct bt_mesh_model_pub * const pub;
/* AppKey List */
u16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT];
uint16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT];
/* Subscription List (group or virtual addresses) */
u16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT];
uint16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT];
const struct bt_mesh_model_op * const op;
@@ -511,11 +535,11 @@ struct bt_mesh_model {
};
struct bt_mesh_send_cb {
void (*start)(u16_t duration, int err, void *cb_data);
void (*start)(uint16_t duration, int err, void *cb_data);
void (*end)(int err, void *cb_data);
};
void bt_mesh_model_msg_init(struct os_mbuf *msg, u32_t opcode);
void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode);
/** Special TTL value to request using configured default TTL */
#define BT_MESH_TTL_DEFAULT 0xff
@@ -574,7 +598,7 @@ struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod);
* if no SIG model with the given ID exists in the given element.
*/
struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem,
u16_t id);
uint16_t id);
/** @brief Find a vendor model.
*
@@ -586,7 +610,7 @@ struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem,
* if no vendor model with the given ID exists in the given element.
*/
struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem,
u16_t company, u16_t id);
uint16_t company, uint16_t id);
/** @brief Get whether the model is in the primary element of the device.
*
@@ -603,13 +627,14 @@ static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod)
*
* @param mod Mesh model.
* @param vnd This is a vendor model.
* @param name Name/key of the settings item.
* @param data Model data to store, or NULL to delete any model data.
* @param data_len Length of the model data.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
const void *data, size_t data_len);
const char *name, const void *data, size_t data_len);
/** @brief Let a model extend another.
*
@@ -637,9 +662,9 @@ int bt_mesh_model_extend(struct bt_mesh_model *mod,
/** Node Composition */
struct bt_mesh_comp {
u16_t cid;
u16_t pid;
u16_t vid;
uint16_t cid;
uint16_t pid;
uint16_t vid;
size_t elem_count;
struct bt_mesh_elem *elem;

View File

@@ -0,0 +1,409 @@
/* 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);
}
/**
* @brief Atomically set a bit to a given value.
*
* Atomically set bit number @a bit of @a target to value @a val.
* 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).
* @param val true for 1, false for 0.
*
* @return N/A
*/
static inline void atomic_set_bit_to(atomic_t *target, int bit, bool val)
{
atomic_val_t mask = ATOMIC_MASK(bit);
if (val) {
(void)atomic_or(ATOMIC_ELEM(target, bit), mask);
} else {
(void)atomic_and(ATOMIC_ELEM(target, bit), ~mask);
}
}
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* __ATOMIC_H__ */

View File

@@ -0,0 +1,267 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BLUETOOTH_MESH_CDB_H_
#define _BLUETOOTH_MESH_CDB_H_
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH_CDB)
#define NODE_COUNT CONFIG_BT_MESH_NODE_COUNT
#define SUBNET_COUNT CONFIG_BT_MESH_SUBNET_COUNT
#define APP_KEY_COUNT CONFIG_BT_MESH_APP_KEY_COUNT
#else
#define NODE_COUNT 0
#define SUBNET_COUNT 0
#define APP_KEY_COUNT 0
#endif
#include "atomic.h"
enum {
BT_MESH_CDB_NODE_CONFIGURED,
BT_MESH_CDB_NODE_BLACKLISTED,
BT_MESH_CDB_NODE_FLAG_COUNT
};
struct bt_mesh_cdb_node {
uint8_t uuid[16];
uint16_t addr;
uint16_t net_idx;
uint8_t num_elem;
uint8_t dev_key[16];
ATOMIC_DEFINE(flags, BT_MESH_CDB_NODE_FLAG_COUNT);
};
struct bt_mesh_cdb_subnet {
uint16_t net_idx;
bool kr_flag;
uint8_t kr_phase;
struct {
uint8_t net_key[16];
} keys[2];
};
struct bt_mesh_cdb_app_key {
uint16_t net_idx;
uint16_t app_idx;
struct {
uint8_t app_key[16];
} keys[2];
};
enum {
BT_MESH_CDB_VALID,
BT_MESH_CDB_SUBNET_PENDING,
BT_MESH_CDB_KEYS_PENDING,
BT_MESH_CDB_NODES_PENDING,
BT_MESH_CDB_IVU_IN_PROGRESS,
BT_MESH_CDB_FLAG_COUNT,
};
struct bt_mesh_cdb {
uint32_t iv_index;
ATOMIC_DEFINE(flags, BT_MESH_CDB_FLAG_COUNT);
struct bt_mesh_cdb_node nodes[NODE_COUNT];
struct bt_mesh_cdb_subnet subnets[SUBNET_COUNT];
struct bt_mesh_cdb_app_key app_keys[APP_KEY_COUNT];
};
extern struct bt_mesh_cdb bt_mesh_cdb;
/** @brief Create the Mesh Configuration Database.
*
* Create and initialize the Mesh Configuration Database. A primary subnet,
* ie one with NetIdx 0, will be added and the provided key will be used as
* NetKey for that subnet.
*
* @param key The NetKey to be used for the primary subnet.
*
* @return 0 on success or negative error code on failure.
*/
int bt_mesh_cdb_create(const uint8_t key[16]);
/** @brief Clear the Mesh Configuration Database.
*
* Remove all nodes, subnets and app-keys stored in the database and mark
* the database as invalid. The data will be cleared from persistent storage
* if CONFIG_BT_SETTINGS is enabled.
*/
void bt_mesh_cdb_clear(void);
/** @brief Set and store the IV Index and IV Update flag.
*
* The IV Index stored in the CDB will be the one used during provisioning
* of new nodes. This function is generally only used from inside the stack.
*
* This function will store the data to persistent storage if
* CONFIG_BT_SETTINGS is enabled.
*
* @param iv_index The new IV Index to use.
* @param iv_update True if there is an ongoing IV Update procedure.
*/
void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update);
/** @brief Allocate a node.
*
* Allocate a new node in the CDB.
*
* @param uuid UUID of the node.
* @param addr Address of the node's primary element. If 0, the lowest
* possible address available will be assigned to the node.
* @param num_elem Number of elements that the node has.
* @param net_idx NetIdx that the node was provisioned to.
*
* @return The new node or NULL if it cannot be allocated.
*/
struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t addr,
uint8_t num_elem, uint16_t net_idx);
/** @brief Delete a node.
*
* Delete a node from the CDB.
*
* @param node The node to be deleted.
* @param store If true, the node will be cleared from persistent storage.
*/
void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store);
/** @brief Get a node by address.
*
* Try to find the node that has the provided address assigned to one of its
* elements.
*
* @param addr Address of the element to look for.
*
* @return The node that has an element with address addr or NULL if no such
* node exists.
*/
struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr);
/** @brief Store node to persistent storage.
*
* @param node Node to be stored.
*/
void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node);
enum {
BT_MESH_CDB_ITER_STOP = 0,
BT_MESH_CDB_ITER_CONTINUE,
};
/** @typedef bt_mesh_cdb_node_func_t
* @brief Node iterator callback.
*
* @param node Node found.
* @param user_data Data given.
*
* @return BT_MESH_CDB_ITER_CONTINUE to continue to iterate through the nodes
* or BT_MESH_CDB_ITER_STOP to stop.
*/
typedef uint8_t (*bt_mesh_cdb_node_func_t)(struct bt_mesh_cdb_node *node,
void *user_data);
/** @brief Node iterator.
*
* Iterate nodes in the Mesh Configuration Database. The callback function
* will only be called for valid, ie allocated, nodes.
*
* @param func Callback function.
* @param user_data Data to pass to the callback.
*/
void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data);
/** @brief Allocate a subnet.
*
* Allocate a new subnet in the CDB.
*
* @param net_idx NetIdx of the subnet.
*
* @return The new subnet or NULL if it cannot be allocated.
*/
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_alloc(uint16_t net_idx);
/** @brief Delete a subnet.
*
* Delete a subnet from the CDB.
*
* @param sub The subnet to be deleted.
* @param store If true, the subnet will be cleared from persistent storage.
*/
void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store);
/** @brief Get a subnet by NetIdx
*
* Try to find the subnet with the specified NetIdx.
*
* @param net_idx NetIdx of the subnet to look for.
*
* @return The subnet with the specified NetIdx or NULL if no such subnet
* exists.
*/
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx);
/** @brief Store subnet to persistent storage.
*
* @param sub Subnet to be stored.
*/
void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub);
/** @brief Get the flags for a subnet
*
* @param sub The subnet to get flags for.
*
* @return The flags for the subnet.
*/
uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub);
/** @brief Allocate an application key.
*
* Allocate a new application key in the CDB.
*
* @param net_idx NetIdx of NetKey that the application key is bound to.
* @param app_idx AppIdx of the application key.
*
* @return The new application key or NULL if it cannot be allocated.
*/
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(uint16_t net_idx,
uint16_t app_idx);
/** @brief Delete an application key.
*
* Delete an application key from the CDB.
*
* @param key The application key to be deleted.
* @param store If true, the key will be cleared from persistent storage.
*/
void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store);
/** @brief Get an application key by AppIdx
*
* Try to find the application key with the specified AppIdx.
*
* @param app_idx AppIdx of the application key to look for.
*
* @return The application key with the specified AppIdx or NULL if no such key
* exists.
*/
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx);
/** @brief Store application key to persistent storage.
*
* @param key Application key to be stored.
*/
void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key);
#endif /* ZEPHYR_INCLUDE_BLUETOOTH_MESH_CDB_H_ */

View File

@@ -0,0 +1,485 @@
/** @file
* @brief Bluetooth Mesh Runtime Configuration APIs.
*/
/*
* Copyright (c) 2020 Nordic Semiconductor
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BT_MESH_CFG_H_
#define _BT_MESH_CFG_H_
#include <stdbool.h>
#include <stddef.h>
#include <sys/types.h>
/**
* @brief Bluetooth Mesh Runtime Configuration API
* @defgroup bt_mesh_cfg Bluetooth Mesh Runtime Configuration
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** Bluetooth Mesh Feature states */
enum bt_mesh_feat_state {
/** Feature is supported, but disabled. */
BT_MESH_FEATURE_DISABLED,
/** Feature is supported and enabled. */
BT_MESH_FEATURE_ENABLED,
/** Feature is not supported, and cannot be enabled. */
BT_MESH_FEATURE_NOT_SUPPORTED,
};
/* Legacy feature defines */
#define BT_MESH_RELAY_DISABLED BT_MESH_FEATURE_DISABLED
#define BT_MESH_RELAY_ENABLED BT_MESH_FEATURE_ENABLED
#define BT_MESH_RELAY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
#define BT_MESH_BEACON_DISABLED BT_MESH_FEATURE_DISABLED
#define BT_MESH_BEACON_ENABLED BT_MESH_FEATURE_ENABLED
#define BT_MESH_GATT_PROXY_DISABLED BT_MESH_FEATURE_DISABLED
#define BT_MESH_GATT_PROXY_ENABLED BT_MESH_FEATURE_ENABLED
#define BT_MESH_GATT_PROXY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
#define BT_MESH_FRIEND_DISABLED BT_MESH_FEATURE_DISABLED
#define BT_MESH_FRIEND_ENABLED BT_MESH_FEATURE_ENABLED
#define BT_MESH_FRIEND_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
#define BT_MESH_NODE_IDENTITY_STOPPED BT_MESH_FEATURE_DISABLED
#define BT_MESH_NODE_IDENTITY_RUNNING BT_MESH_FEATURE_ENABLED
#define BT_MESH_NODE_IDENTITY_NOT_SUPPORTED BT_MESH_FEATURE_NOT_SUPPORTED
/** @brief Enable or disable sending of the Secure Network Beacon.
*
* @param beacon New Secure Network Beacon state.
*/
void bt_mesh_beacon_set(bool beacon);
/** @brief Get the current Secure Network Beacon state.
*
* @returns Whether the Secure Network Beacon feature is enabled.
*/
bool bt_mesh_beacon_enabled(void);
/** @brief Set the default TTL value.
*
* The default TTL value is used when no explicit TTL value is set. Models will
* use the default TTL value when @ref bt_mesh_msg_ctx::send_ttl is
* @ref BT_MESH_TTL_DEFAULT.
*
* @param default_ttl The new default TTL value. Valid values are 0x00 and 0x02
* to @ref BT_MESH_TTL_MAX.
*
* @retval 0 Successfully set the default TTL value.
* @retval -EINVAL Invalid TTL value.
*/
int bt_mesh_default_ttl_set(uint8_t default_ttl);
/** @brief Get the current default TTL value.
*
* @return The current default TTL value.
*/
uint8_t bt_mesh_default_ttl_get(void);
/** @brief Set the Network Transmit parameters.
*
* The Network Transmit parameters determine the parameters local messages are
* transmitted with.
*
* @see BT_MESH_TRANSMIT
*
* @param xmit New Network Transmit parameters. Use @ref BT_MESH_TRANSMIT for
* encoding.
*/
void bt_mesh_net_transmit_set(uint8_t xmit);
/** @brief Get the current Network Transmit parameters.
*
* The @ref BT_MESH_TRANSMIT_COUNT and @ref BT_MESH_TRANSMIT_INT macros can be
* used to decode the Network Transmit parameters.
*
* @return The current Network Transmit parameters.
*/
uint8_t bt_mesh_net_transmit_get(void);
/** @brief Configure the Relay feature.
*
* Enable or disable the Relay feature, and configure the parameters to
* transmit relayed messages with.
*
* Support for the Relay feature must be enabled through the
* @c CONFIG_BT_MESH_RELAY configuration option.
*
* @see BT_MESH_TRANSMIT
*
* @param relay New Relay feature state. Must be one of
* @ref BT_MESH_FEATURE_ENABLED and
* @ref BT_MESH_FEATURE_DISABLED.
* @param xmit New Relay retransmit parameters. Use @ref BT_MESH_TRANSMIT for
* encoding.
*
* @retval 0 Successfully changed the Relay configuration.
* @retval -ENOTSUP The Relay feature is not supported.
* @retval -EINVAL Invalid parameter.
* @retval -EALREADY Already using the given parameters.
*/
int bt_mesh_relay_set(enum bt_mesh_feat_state relay, uint8_t xmit);
/** @brief Get the current Relay feature state.
*
* @returns The Relay feature state.
*/
enum bt_mesh_feat_state bt_mesh_relay_get(void);
/** @brief Get the current Relay Retransmit parameters.
*
* The @ref BT_MESH_TRANSMIT_COUNT and @ref BT_MESH_TRANSMIT_INT macros can be
* used to decode the Relay Retransmit parameters.
*
* @return The current Relay Retransmit parameters, or 0 if relay is not
* supported.
*/
uint8_t bt_mesh_relay_retransmit_get(void);
/** @brief Enable or disable the GATT Proxy feature.
*
* Support for the GATT Proxy feature must be enabled through the
* @c CONFIG_BT_MESH_GATT_PROXY configuration option.
*
* @note The GATT Proxy feature only controls a Proxy node's ability to relay
* messages to the mesh network. A node that supports GATT Proxy will
* still advertise Connectable Proxy beacons, even if the feature is
* disabled. The Proxy feature can only be fully disabled through compile
* time configuration.
*
* @param gatt_proxy New GATT Proxy state. Must be one of
* @ref BT_MESH_FEATURE_ENABLED and
* @ref BT_MESH_FEATURE_DISABLED.
*
* @retval 0 Successfully changed the GATT Proxy feature state.
* @retval -ENOTSUP The GATT Proxy feature is not supported.
* @retval -EINVAL Invalid parameter.
* @retval -EALREADY Already in the given state.
*/
int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy);
/** @brief Get the current GATT Proxy state.
*
* @returns The GATT Proxy feature state.
*/
enum bt_mesh_feat_state bt_mesh_gatt_proxy_get(void);
/** @brief Enable or disable the Friend feature.
*
* Any active friendships will be terminated immediately if the Friend feature
* is disabled.
*
* Support for the Friend feature must be enabled through the
* @c CONFIG_BT_MESH_FRIEND configuration option.
*
* @param friendship New Friend feature state. Must be one of
* @ref BT_MESH_FEATURE_ENABLED and
* @ref BT_MESH_FEATURE_DISABLED.
*
* @retval 0 Successfully changed the Friend feature state.
* @retval -ENOTSUP The Friend feature is not supported.
* @retval -EINVAL Invalid parameter.
* @retval -EALREADY Already in the given state.
*/
int bt_mesh_friend_set(enum bt_mesh_feat_state friendship);
/** @brief Get the current Friend state.
*
* @returns The Friend feature state.
*/
enum bt_mesh_feat_state bt_mesh_friend_get(void);
/**
* @brief Bluetooth Mesh Subnet Configuration
* @defgroup bt_mesh_cfg_subnet Bluetooth Mesh Subnet Configuration
* @{
*/
/** @brief Add a Subnet.
*
* Adds a subnet with the given network index and network key to the list of
* known Subnets. All messages sent on the given Subnet will be processed by
* this node, and the node may send and receive Network Beacons on the given
* Subnet.
*
* @param net_idx Network index.
* @param key Root network key of the Subnet. All other keys are derived
* from this.
*
* @retval STATUS_SUCCESS The Subnet was successfully added.
* @retval STATUS_INSUFF_RESOURCES No room for this Subnet.
* @retval STATUS_UNSPECIFIED The Subnet couldn't be created for some reason.
*/
uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16]);
/** @brief Update the given Subnet.
*
* Starts the Key Refresh procedure for this Subnet by adding a second set of
* encryption keys. The Subnet will continue sending with the old key (but
* receiving messages using both) until the Subnet enters Key Refresh phase 2.
*
* This allows a network configurator to replace old network and application
* keys for the entire network, effectively removing access for all nodes that
* aren't given the new keys.
*
* @param net_idx Network index.
* @param key New root network key of the Subnet.
*
* @retval STATUS_SUCCESS The Subnet was updated with a second key.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
* @retval STATUS_IDX_ALREADY_STORED The @c key value is the same as the
* current key.
* @retval STATUS_CANNOT_UPDATE The Subnet cannot be updated for some reason.
*/
uint8_t bt_mesh_subnet_update(uint16_t net_idx, const uint8_t key[16]);
/** @brief Delete a Subnet.
*
* Removes the Subnet with the given network index from the node. The node will
* stop sending Network Beacons with the given Subnet, and can no longer
* process messages on this Subnet.
*
* All Applications bound to this Subnet are also deleted.
*
* @param net_idx Network index.
*
* @retval STATUS_SUCCESS The Subnet was deleted.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
*/
uint8_t bt_mesh_subnet_del(uint16_t net_idx);
/** @brief Check whether a Subnet is known.
*
* @param net_idx Network index
*
* @return true if a Subnet with the given index exists, false otherwise.
*/
bool bt_mesh_subnet_exists(uint16_t net_idx);
/** @brief Set the Subnet's Key Refresh phase.
*
* The Key Refresh procedure is started by updating the Subnet keys through
* @ref bt_mesh_subnet_update. This puts the Subnet in Key Refresh Phase 1.
* Once all nodes have received the new Subnet key, Key Refresh Phase 2 can be
* activated through this function to start transmitting with the new network
* key. Finally, to revoke the old key, set the Key Refresh Phase to 3. This
* removes the old keys from the node, and returns the Subnet back to normal
* single-key operation with the new key set.
*
* @param net_idx Network index.
* @param phase Pointer to the new Key Refresh phase. Will return the actual
* Key Refresh phase after updating.
*
* @retval STATUS_SUCCESS The Key Refresh phase of the Subnet was successfully
* changed.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
* @retval STATUS_CANNOT_UPDATE The given phase change is invalid.
*/
uint8_t bt_mesh_subnet_kr_phase_set(uint16_t net_idx, uint8_t *phase);
/** @brief Get the Subnet's Key Refresh phase.
*
* @param net_idx Network index.
* @param phase Pointer to the Key Refresh variable to fill.
*
* @retval STATUS_SUCCESS Successfully populated the @c phase variable.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
*/
uint8_t bt_mesh_subnet_kr_phase_get(uint16_t net_idx, uint8_t *phase);
/** @brief Set the Node Identity state of the Subnet.
*
* The Node Identity state of a Subnet determines whether the Subnet advertises
* connectable Node Identity beacons for Proxy Clients to connect to.
* Once started, the Node Identity beacon runs for 60 seconds, or until it is
* stopped.
*
* This function serves the same purpose as @ref bt_mesh_proxy_identity_enable,
* but only acts on a single Subnet.
*
* GATT Proxy support must be enabled through
* @option{CONFIG_BT_MESH_GATT_PROXY}.
*
* @param net_idx Network index.
* @param node_id New Node Identity state, must be either @ref
* BT_MESH_FEATURE_ENABLED or @ref BT_MESH_FEATURE_DISABLED.
*
* @retval STATUS_SUCCESS Successfully set the Node Identity state of the
* Subnet.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
* @retval STATUS_FEAT_NOT_SUPP The Node Identity feature is not supported.
* @retval STATUS_CANNOT_SET Couldn't set the Node Identity state.
*/
uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx,
enum bt_mesh_feat_state node_id);
/** @brief Get the Node Identity state of the Subnet.
*
* @param net_idx Network index.
* @param node_id Node Identity variable to fill.
*
* @retval STATUS_SUCCESS Successfully populated the @c node_id variable.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
*/
uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx,
enum bt_mesh_feat_state *node_id);
/** @brief Get a list of all known Subnet indexes.
*
* Builds a list of all known Subnet indexes in the @c net_idxs array.
* If the @c net_idxs array is smaller than the list of known Subnets, this
* function fills all available entries and returns @c -ENOMEM. In this
* case, the next @c max entries of the list can be read out by calling
* @code
* bt_mesh_subnets_get(list, max, max);
* @endcode
*
* Note that any changes to the Subnet list between calls to this function
* could change the order and number of entries in the list.
*
* @param net_idxs Array to fill.
* @param max Max number of indexes to return.
* @param skip Number of indexes to skip. Enables batched processing of the
* list.
*
* @return The number of indexes added to the @c net_idxs array, or @c -ENOMEM
* if the number of known Subnets exceeds the @c max parameter.
*/
ssize_t bt_mesh_subnets_get(uint16_t net_idxs[], size_t max, off_t skip);
/**
* @}
*/
/**
* @brief Bluetooth Mesh Application Configuration
* @defgroup bt_mesh_cfg_app Bluetooth Mesh Application Configuration
* @{
*/
/** @brief Add an Application key.
*
* Adds the Application with the given index to the list of known applications.
* Allows the node to send and receive model messages encrypted with this
* Application key.
*
* Every Application is bound to a specific Subnet. The node must know the
* Subnet the Application is bound to before it can add the Application.
*
* @param app_idx Application index.
* @param net_idx Network index the Application is bound to.
* @param key Application key value.
*
* @retval STATUS_SUCCESS The Application was successfully added.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
* @retval STATUS_INSUFF_RESOURCES There's no room for storing this
* Application.
* @retval STATUS_INVALID_BINDING This AppIdx is already bound to another
* Subnet.
* @retval STATUS_IDX_ALREADY_STORED This AppIdx is already stored with a
* different key value.
* @retval STATUS_CANNOT_SET Cannot set the Application key for some reason.
*/
uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx,
const uint8_t key[16]);
/** @brief Update an Application key.
*
* Update an Application with a second Application key, as part of the
* Key Refresh procedure of the bound Subnet. The node will continue
* transmitting with the old application key (but receiving on both) until the
* Subnet enters Key Refresh phase 2. Once the Subnet enters Key Refresh phase
* 3, the old application key will be deleted.
*
* @note The Application key can only be updated if the bound Subnet is in Key
* Refresh phase 1.
*
* @param app_idx Application index.
* @param net_idx Network index the Application is bound to, or
* @ref BT_MESH_KEY_ANY to skip the binding check.
* @param key New key value.
*
* @retval STATUS_SUCCESS The Application key was successfully updated.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
* @retval STATUS_INVALID_BINDING This AppIdx is not bound to the given NetIdx.
* @retval STATUS_CANNOT_UPDATE The Application key cannot be updated for some
* reason.
* @retval STATUS_IDX_ALREADY_STORED This AppIdx is already updated with a
* different key value.
*/
uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx,
const uint8_t key[16]);
/** @brief Delete an Application key.
*
* All models bound to this application will remove this binding.
* All models publishing with this application will stop publishing.
*
* @param app_idx Application index.
* @param net_idx Network index.
*
* @retval STATUS_SUCCESS The Application key was successfully deleted.
* @retval STATUS_INVALID_NETKEY The NetIdx is unknown.
* @retval STATUS_INVALID_BINDING This AppIdx is not bound to the given NetIdx.
*/
uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx);
/** @brief Check if an Application key is known.
*
* @param app_idx Application index.
*
* @return true if the Application is known, false otherwise.
*/
bool bt_mesh_app_key_exists(uint16_t app_idx);
/** @brief Get a list of all known Application key indexes.
*
* Builds a list of all Application indexes for the given network index in the
* @c app_idxs array. If the @c app_idxs array cannot fit all bound
* Applications, this function fills all available entries and returns @c
* -ENOMEM. In this case, the next @c max entries of the list can be read out
* by calling
* @code
* bt_mesh_app_keys_get(net_idx, list, max, max);
* @endcode
*
* Note that any changes to the Application key list between calls to this
* function could change the order and number of entries in the list.
*
* @param net_idx Network Index to get the Applications of, or @ref
* BT_MESH_KEY_ANY to get all Applications.
* @param app_idxs Array to fill.
* @param max Max number of indexes to return.
* @param skip Number of indexes to skip. Enables batched processing of the
* list.
*
* @return The number of indexes added to the @c app_idxs array, or @c -ENOMEM
* if the number of known Applications exceeds the @c max parameter.
*/
ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max,
off_t skip);
/**
* @}
*/
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* _BT_MESH_CFG_H_ */

View File

@@ -26,7 +26,7 @@ struct bt_mesh_cfg_cli {
struct bt_mesh_model *model;
struct k_sem op_sync;
u32_t op_pending;
uint32_t op_pending;
void *op_param;
};
@@ -37,45 +37,81 @@ extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb;
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_op, NULL, \
cli_data, &bt_mesh_cfg_cli_cb)
int bt_mesh_cfg_comp_data_get(u16_t net_idx, u16_t addr, u8_t page,
u8_t *status, struct os_mbuf *comp);
int bt_mesh_cfg_node_reset(uint16_t net_idx, uint16_t addr, bool *status);
int bt_mesh_cfg_beacon_get(u16_t net_idx, u16_t addr, u8_t *status);
int bt_mesh_cfg_comp_data_get(uint16_t net_idx, uint16_t addr, uint8_t page,
uint8_t *status, struct os_mbuf *comp);
int bt_mesh_cfg_beacon_set(u16_t net_idx, u16_t addr, u8_t val, u8_t *status);
int bt_mesh_cfg_beacon_get(uint16_t net_idx, uint16_t addr, uint8_t *status);
int bt_mesh_cfg_ttl_get(u16_t net_idx, u16_t addr, u8_t *ttl);
int bt_mesh_cfg_beacon_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status);
int bt_mesh_cfg_ttl_set(u16_t net_idx, u16_t addr, u8_t val, u8_t *ttl);
int bt_mesh_cfg_ttl_get(uint16_t net_idx, uint16_t addr, uint8_t *ttl);
int bt_mesh_cfg_friend_get(u16_t net_idx, u16_t addr, u8_t *status);
int bt_mesh_cfg_ttl_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *ttl);
int bt_mesh_cfg_friend_set(u16_t net_idx, u16_t addr, u8_t val, u8_t *status);
int bt_mesh_cfg_friend_get(uint16_t net_idx, uint16_t addr, uint8_t *status);
int bt_mesh_cfg_gatt_proxy_get(u16_t net_idx, u16_t addr, u8_t *status);
int bt_mesh_cfg_friend_set(uint16_t net_idx, uint16_t addr, uint8_t val, uint8_t *status);
int bt_mesh_cfg_gatt_proxy_set(u16_t net_idx, u16_t addr, u8_t val,
u8_t *status);
int bt_mesh_cfg_gatt_proxy_get(uint16_t net_idx, uint16_t addr, uint8_t *status);
int bt_mesh_cfg_relay_get(u16_t net_idx, u16_t addr, u8_t *status,
u8_t *transmit);
int bt_mesh_cfg_gatt_proxy_set(uint16_t net_idx, uint16_t addr, uint8_t val,
uint8_t *status);
int bt_mesh_cfg_relay_set(u16_t net_idx, u16_t addr, u8_t new_relay,
u8_t new_transmit, u8_t *status, u8_t *transmit);
int bt_mesh_cfg_net_transmit_get(uint16_t net_idx, uint16_t addr,
uint8_t *transmit);
int bt_mesh_cfg_net_key_add(u16_t net_idx, u16_t addr, u16_t key_net_idx,
const u8_t net_key[16], u8_t *status);
int bt_mesh_cfg_net_transmit_set(uint16_t net_idx, uint16_t addr,
uint8_t val, uint8_t *transmit);
int bt_mesh_cfg_app_key_add(u16_t net_idx, u16_t addr, u16_t key_net_idx,
u16_t key_app_idx, const u8_t app_key[16],
u8_t *status);
int bt_mesh_cfg_relay_get(uint16_t net_idx, uint16_t addr, uint8_t *status,
uint8_t *transmit);
int bt_mesh_cfg_mod_app_bind(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_app_idx, u16_t mod_id, u8_t *status);
int bt_mesh_cfg_relay_set(uint16_t net_idx, uint16_t addr, uint8_t new_relay,
uint8_t new_transmit, uint8_t *status, uint8_t *transmit);
int bt_mesh_cfg_mod_app_bind_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_app_idx, u16_t mod_id, u16_t cid,
u8_t *status);
int bt_mesh_cfg_net_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx,
const uint8_t net_key[16], uint8_t *status);
int bt_mesh_cfg_net_key_get(uint16_t net_idx, uint16_t addr, uint16_t *keys,
size_t *key_cnt);
int bt_mesh_cfg_net_key_del(uint16_t net_idx, uint16_t addr,
uint16_t key_net_idx, uint8_t *status);
int bt_mesh_cfg_app_key_add(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx,
uint16_t key_app_idx, const uint8_t app_key[16],
uint8_t *status);
int bt_mesh_cfg_app_key_get(uint16_t net_idx, uint16_t addr, uint16_t key_net_idx,
uint8_t *status, uint16_t *keys, size_t *key_cnt);
int bt_mesh_cfg_app_key_del(uint16_t net_idx, uint16_t addr,
uint16_t key_net_idx, uint16_t key_app_idx, uint8_t *status);
int bt_mesh_cfg_mod_app_bind(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_app_idx, uint16_t mod_id, uint8_t *status);
int bt_mesh_cfg_mod_app_unbind(uint16_t net_idx, uint16_t addr,
uint16_t elem_addr, uint16_t mod_app_idx,
uint16_t mod_id, uint8_t *status);
int bt_mesh_cfg_mod_app_bind_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_app_idx, uint16_t mod_id, uint16_t cid,
uint8_t *status);
int bt_mesh_cfg_mod_app_unbind_vnd(uint16_t net_idx, uint16_t addr,
uint16_t elem_addr, uint16_t mod_app_idx, uint16_t mod_id,
uint16_t cid, uint8_t *status);
int bt_mesh_cfg_mod_app_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_id, uint8_t *status, uint16_t *apps,
size_t *app_cnt);
int bt_mesh_cfg_mod_app_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_id, uint16_t cid, uint8_t *status,
uint16_t *apps, size_t *app_cnt);
/** @def BT_MESH_PUB_PERIOD_100MS
*
@@ -120,109 +156,117 @@ int bt_mesh_cfg_mod_app_bind_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
#define BT_MESH_PUB_PERIOD_10MIN(steps) (((steps) & BIT_MASK(6)) | (3 << 6))
struct bt_mesh_cfg_mod_pub {
u16_t addr;
u16_t app_idx;
uint16_t addr;
uint16_t app_idx;
bool cred_flag;
u8_t ttl;
u8_t period;
u8_t transmit;
uint8_t ttl;
uint8_t period;
uint8_t transmit;
};
int bt_mesh_cfg_mod_pub_get(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_id, struct bt_mesh_cfg_mod_pub *pub,
u8_t *status);
int bt_mesh_cfg_mod_pub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_id, struct bt_mesh_cfg_mod_pub *pub,
uint8_t *status);
int bt_mesh_cfg_mod_pub_get_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_id, u16_t cid,
struct bt_mesh_cfg_mod_pub *pub, u8_t *status);
int bt_mesh_cfg_mod_pub_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_id, uint16_t cid,
struct bt_mesh_cfg_mod_pub *pub, uint8_t *status);
int bt_mesh_cfg_mod_pub_set(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_id, struct bt_mesh_cfg_mod_pub *pub,
u8_t *status);
int bt_mesh_cfg_mod_pub_set(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_id, struct bt_mesh_cfg_mod_pub *pub,
uint8_t *status);
int bt_mesh_cfg_mod_pub_set_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t mod_id, u16_t cid,
struct bt_mesh_cfg_mod_pub *pub, u8_t *status);
int bt_mesh_cfg_mod_pub_set_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_id, uint16_t cid,
struct bt_mesh_cfg_mod_pub *pub, uint8_t *status);
int bt_mesh_cfg_mod_sub_add(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u8_t *status);
int bt_mesh_cfg_mod_sub_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t sub_addr, uint16_t mod_id, uint8_t *status);
int bt_mesh_cfg_mod_sub_add_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u16_t cid,
u8_t *status);
int bt_mesh_cfg_mod_sub_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t sub_addr, uint16_t mod_id, uint16_t cid,
uint8_t *status);
int bt_mesh_cfg_mod_sub_del(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u8_t *status);
int bt_mesh_cfg_mod_sub_del(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t sub_addr, uint16_t mod_id, uint8_t *status);
int bt_mesh_cfg_mod_sub_del_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u16_t cid,
u8_t *status);
int bt_mesh_cfg_mod_sub_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t sub_addr, uint16_t mod_id, uint16_t cid,
uint8_t *status);
int bt_mesh_cfg_mod_sub_overwrite(u16_t net_idx, u16_t addr, u16_t elem_addr,
u16_t sub_addr, u16_t mod_id, u8_t *status);
int bt_mesh_cfg_mod_sub_overwrite(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t sub_addr, uint16_t mod_id, uint8_t *status);
int bt_mesh_cfg_mod_sub_overwrite_vnd(u16_t net_idx, u16_t addr,
u16_t elem_addr, u16_t sub_addr,
u16_t mod_id, u16_t cid, u8_t *status);
int bt_mesh_cfg_mod_sub_overwrite_vnd(uint16_t net_idx, uint16_t addr,
uint16_t elem_addr, uint16_t sub_addr,
uint16_t mod_id, uint16_t cid, uint8_t *status);
int bt_mesh_cfg_mod_sub_va_add(u16_t net_idx, u16_t addr, u16_t elem_addr,
const u8_t label[16], u16_t mod_id,
u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_add(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
const uint8_t label[16], uint16_t mod_id,
uint16_t *virt_addr, uint8_t *status);
int bt_mesh_cfg_mod_sub_va_add_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
const u8_t label[16], u16_t mod_id,
u16_t cid, u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_add_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
const uint8_t label[16], uint16_t mod_id,
uint16_t cid, uint16_t *virt_addr, uint8_t *status);
int bt_mesh_cfg_mod_sub_va_del(u16_t net_idx, u16_t addr, u16_t elem_addr,
const u8_t label[16], u16_t mod_id,
u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_del(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
const uint8_t label[16], uint16_t mod_id,
uint16_t *virt_addr, uint8_t *status);
int bt_mesh_cfg_mod_sub_va_del_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
const u8_t label[16], u16_t mod_id,
u16_t cid, u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_del_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
const uint8_t label[16], uint16_t mod_id,
uint16_t cid, uint16_t *virt_addr, uint8_t *status);
int bt_mesh_cfg_mod_sub_va_overwrite(u16_t net_idx, u16_t addr,
u16_t elem_addr, const u8_t label[16],
u16_t mod_id, u16_t *virt_addr,
u8_t *status);
int bt_mesh_cfg_mod_sub_va_overwrite(uint16_t net_idx, uint16_t addr,
uint16_t elem_addr, const uint8_t label[16],
uint16_t mod_id, uint16_t *virt_addr,
uint8_t *status);
int bt_mesh_cfg_mod_sub_va_overwrite_vnd(u16_t net_idx, u16_t addr,
u16_t elem_addr, const u8_t label[16],
u16_t mod_id, u16_t cid,
u16_t *virt_addr, u8_t *status);
int bt_mesh_cfg_mod_sub_va_overwrite_vnd(uint16_t net_idx, uint16_t addr,
uint16_t elem_addr, const uint8_t label[16],
uint16_t mod_id, uint16_t cid,
uint16_t *virt_addr, uint8_t *status);
int bt_mesh_cfg_mod_sub_get(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_id, uint8_t *status, uint16_t *subs,
size_t *sub_cnt);
int bt_mesh_cfg_mod_sub_get_vnd(uint16_t net_idx, uint16_t addr, uint16_t elem_addr,
uint16_t mod_id, uint16_t cid, uint8_t *status,
uint16_t *subs, size_t *sub_cnt);
struct bt_mesh_cfg_hb_sub {
u16_t src;
u16_t dst;
u8_t period;
u8_t count;
u8_t min;
u8_t max;
uint16_t src;
uint16_t dst;
uint8_t period;
uint8_t count;
uint8_t min;
uint8_t max;
};
int bt_mesh_cfg_hb_sub_set(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_sub *sub, u8_t *status);
int bt_mesh_cfg_hb_sub_set(uint16_t net_idx, uint16_t addr,
struct bt_mesh_cfg_hb_sub *sub, uint8_t *status);
int bt_mesh_cfg_hb_sub_get(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_sub *sub, u8_t *status);
int bt_mesh_cfg_hb_sub_get(uint16_t net_idx, uint16_t addr,
struct bt_mesh_cfg_hb_sub *sub, uint8_t *status);
struct bt_mesh_cfg_hb_pub {
u16_t dst;
u8_t count;
u8_t period;
u8_t ttl;
u16_t feat;
u16_t net_idx;
uint16_t dst;
uint8_t count;
uint8_t period;
uint8_t ttl;
uint16_t feat;
uint16_t net_idx;
};
int bt_mesh_cfg_hb_pub_set(u16_t net_idx, u16_t addr,
const struct bt_mesh_cfg_hb_pub *pub, u8_t *status);
int bt_mesh_cfg_hb_pub_set(uint16_t net_idx, uint16_t addr,
const struct bt_mesh_cfg_hb_pub *pub, uint8_t *status);
int bt_mesh_cfg_hb_pub_get(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_pub *pub, u8_t *status);
int bt_mesh_cfg_hb_pub_get(uint16_t net_idx, uint16_t addr,
struct bt_mesh_cfg_hb_pub *pub, uint8_t *status);
s32_t bt_mesh_cfg_cli_timeout_get(void);
void bt_mesh_cfg_cli_timeout_set(s32_t timeout);
int32_t bt_mesh_cfg_cli_timeout_get(void);
void bt_mesh_cfg_cli_timeout_set(int32_t timeout);
#ifdef __cplusplus
}

View File

@@ -21,51 +21,13 @@
extern "C" {
#endif
/** Mesh Configuration Server Model Context */
struct bt_mesh_cfg_srv {
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 bt_mesh_hb_pub {
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 bt_mesh_hb_sub {
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_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb;
#define BT_MESH_MODEL_CFG_SRV(srv_data) \
#define BT_MESH_MODEL_CFG_SRV \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_op, NULL, \
srv_data, &bt_mesh_cfg_srv_cb)
NULL, &bt_mesh_cfg_srv_cb)
#ifdef __cplusplus
}

View File

@@ -62,15 +62,6 @@
extern "C" {
#endif
#define u8_t uint8_t
#define s8_t int8_t
#define u16_t uint16_t
#define s16_t int16_t
#define u32_t uint32_t
#define u64_t uint64_t
#define s64_t int64_t
#define s32_t int32_t
/** @brief Helper to declare elements of bt_data arrays
*
* This macro is mainly for creating an array of struct bt_data
@@ -84,7 +75,7 @@ extern "C" {
{ \
.type = (_type), \
.data_len = (_data_len), \
.data = (const u8_t *)(_data), \
.data = (const uint8_t *)(_data), \
}
/** @brief Helper to declare elements of bt_data arrays
@@ -96,8 +87,8 @@ extern "C" {
* @param _bytes Variable number of single-byte parameters
*/
#define BT_DATA_BYTES(_type, _bytes...) \
BT_DATA(_type, ((u8_t []) { _bytes }), \
sizeof((u8_t []) { _bytes }))
BT_DATA(_type, ((uint8_t []) { _bytes }), \
sizeof((uint8_t []) { _bytes }))
/* EIR/AD data type definitions */
#define BT_DATA_FLAGS 0x01 /* AD flags */
@@ -130,9 +121,13 @@ extern "C" {
#define sys_put_be16(a,b) put_be16(b, a)
#define sys_put_le16(a,b) put_le16(b, a)
#define sys_put_le24(a,b) put_le24(b, a)
#define sys_put_be24(a,b) put_be24(b, a)
#define sys_put_be32(a,b) put_be32(b, a)
#define sys_get_be16(a) get_be16(a)
#define sys_get_be24(a) get_be24(a)
#define sys_get_le16(a) get_le16(a)
#define sys_get_le24(a) get_le24(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)
@@ -207,9 +202,9 @@ typedef ble_addr_t bt_addr_le_t;
struct net_buf_simple_state {
/** Offset of the data pointer from the beginning of the storage */
u16_t offset;
uint16_t offset;
/** Length of data */
u16_t len;
uint16_t len;
};
static inline struct os_mbuf * NET_BUF_SIMPLE(uint16_t size)
@@ -249,6 +244,14 @@ static inline void net_buf_simple_init(struct os_mbuf *buf,
buf->om_len = 0;
}
#define net_buf_simple_init_with_data(buf, data, size) \
os_mbuf_copyinto(buf, 0, data, size);
static inline void net_buf_simple_reset(struct os_mbuf *om)
{
net_buf_simple_init(om, 0);
}
void net_buf_put(struct ble_npl_eventq *fifo, struct os_mbuf *buf);
void * net_buf_ref(struct os_mbuf *om);
void net_buf_unref(struct os_mbuf *om);
@@ -259,18 +262,20 @@ uint32_t net_buf_simple_pull_le32(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_le24(struct os_mbuf *om, uint32_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_simple_add_le32(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_be24(struct os_mbuf *om, uint32_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_pull_mem(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 ble_npl_eventq *q);
void *net_buf_get(struct ble_npl_eventq *fifo,s32_t t);
void *net_buf_get(struct ble_npl_eventq *fifo,int32_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);
@@ -282,7 +287,7 @@ void net_buf_reserve(struct os_mbuf *om, size_t reserve);
#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 net_buf_pull(a, b) net_buf_simple_pull(a, b)
#define net_buf_pull(a, b) net_buf_simple_pull_mem(a, b)
#define net_buf_pull_mem(a, b) net_buf_simple_pull_mem(a, b)
#define net_buf_pull_u8(a) net_buf_simple_pull_u8(a)
#define net_buf_pull_be16(a) net_buf_simple_pull_be16(a)
@@ -290,14 +295,22 @@ void net_buf_reserve(struct os_mbuf *om, size_t reserve);
#define BT_GATT_CCC_NOTIFY BLE_GATT_CHR_PROP_NOTIFY
#ifndef MIN
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
/** 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;
uint8_t type;
uint8_t data_len;
const uint8_t *data;
};
struct bt_pub_key_cb {
@@ -309,18 +322,24 @@ struct bt_pub_key_cb {
*
* @param key The local public key, or NULL in case of no key.
*/
void (*func)(const u8_t key[64]);
void (*func)(const uint8_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);
typedef void (*bt_dh_key_cb_t)(const uint8_t key[32]);
int bt_dh_key_gen(const uint8_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);
int bt_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *enc_data,
size_t len, const uint8_t *aad, size_t aad_len,
uint8_t *plaintext, size_t mic_size);
int bt_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *enc_data,
size_t len, const uint8_t *aad, size_t aad_len,
uint8_t *plaintext, size_t mic_size);
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,
@@ -334,9 +353,10 @@ struct k_delayed_work {
void k_work_init(struct ble_npl_callout *work, ble_npl_event_fn handler);
void k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f);
void k_delayed_work_cancel(struct k_delayed_work *w);
bool k_delayed_work_pending(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);
uint32_t k_uptime_get_32(void);
void k_sleep(int32_t duration);
void k_work_submit(struct ble_npl_callout *w);
void k_work_add_arg(struct ble_npl_callout *w, void *arg);
@@ -366,18 +386,18 @@ static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
src += length - 1;
for (; length > 0; length--) {
*((u8_t *)dst++) = *((u8_t *)src--);
*((uint8_t *)dst++) = *((uint8_t *)src--);
}
}
#define popcount(x) __builtin_popcount(x)
static inline unsigned int find_lsb_set(u32_t op)
static inline unsigned int find_lsb_set(uint32_t op)
{
return __builtin_ffs(op);
}
static inline unsigned int find_msb_set(u32_t op)
static inline unsigned int find_msb_set(uint32_t op)
{
if (!op)
return 0;
@@ -385,43 +405,61 @@ static inline unsigned int find_msb_set(u32_t op)
return 32 - __builtin_clz(op);
}
#define CONFIG_BT_MESH_FRIEND BLE_MESH_FRIEND
#define CONFIG_BT_MESH_GATT_PROXY BLE_MESH_GATT_PROXY
#define CONFIG_BT_MESH_IV_UPDATE_TEST BLE_MESH_IV_UPDATE_TEST
#define CONFIG_BT_MESH_LOW_POWER BLE_MESH_LOW_POWER
#define CONFIG_BT_MESH_LPN_AUTO BLE_MESH_LPN_AUTO
#define CONFIG_BT_MESH_LPN_ESTABLISHMENT BLE_MESH_LPN_ESTABLISHMENT
#define CONFIG_BT_MESH_PB_ADV BLE_MESH_PB_ADV
#define CONFIG_BT_MESH_PB_GATT BLE_MESH_PB_GATT
#define CONFIG_BT_MESH_PROV BLE_MESH_PROV
#define CONFIG_BT_MESH_PROXY BLE_MESH_PROXY
#define CONFIG_BT_TESTING BLE_MESH_TESTING
#define CONFIG_BT_SETTINGS BLE_MESH_SETTINGS
#define CONFIG_SETTINGS BLE_MESH_SETTINGS
#define CONFIG_BT_MESH_PROVISIONER BLE_MESH_PROVISIONER
#define CONFIG_BT_MESH_FRIEND BLE_MESH_FRIEND
#define CONFIG_BT_MESH_GATT_PROXY BLE_MESH_GATT_PROXY
#define CONFIG_BT_MESH_IV_UPDATE_TEST BLE_MESH_IV_UPDATE_TEST
#define CONFIG_BT_MESH_LOW_POWER BLE_MESH_LOW_POWER
#define CONFIG_BT_MESH_LPN_SUB_ALL_NODES_ADDR BLE_MESH_LPN_SUB_ALL_NODES_ADDR
#define CONFIG_BT_MESH_LPN_AUTO BLE_MESH_LPN_AUTO
#define CONFIG_BT_MESH_LPN_ESTABLISHMENT BLE_MESH_LPN_ESTABLISHMENT
#define CONFIG_BT_MESH_PB_ADV BLE_MESH_PB_ADV
#define CONFIG_BT_MESH_PB_GATT BLE_MESH_PB_GATT
#define CONFIG_BT_MESH_PROV BLE_MESH_PROV
#define CONFIG_BT_MESH_PROXY BLE_MESH_PROXY
#define CONFIG_BT_TESTING BLE_MESH_TESTING
#define CONFIG_BT_SETTINGS BLE_MESH_SETTINGS
#define CONFIG_SETTINGS BLE_MESH_SETTINGS
#define CONFIG_BT_MESH_PROVISIONER BLE_MESH_PROVISIONER
#define CONFIG_BT_MESH_PROV_DEVICE BLE_MESH_PROV_DEVICE
#define CONFIG_BT_MESH_CDB BLE_MESH_CDB
/* Above flags are used with IS_ENABLED macro */
#define IS_ENABLED(config) MYNEWT_VAL(config)
#define CONFIG_BT_MESH_LPN_GROUPS MYNEWT_VAL(BLE_MESH_LPN_GROUPS)
#define CONFIG_BT_MESH_ADV_BUF_COUNT MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)
#define CONFIG_BT_MESH_FRIEND_QUEUE_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE)
#define CONFIG_BT_MESH_FRIEND_RECV_WIN MYNEWT_VAL(BLE_MESH_FRIEND_RECV_WIN)
#define CONFIG_BT_MESH_LPN_POLL_TIMEOUT MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT)
#define CONFIG_BT_MESH_MODEL_GROUP_COUNT MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT)
#define CONFIG_BT_MESH_MODEL_KEY_COUNT MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT)
#define CONFIG_BT_MESH_NODE_ID_TIMEOUT MYNEWT_VAL(BLE_MESH_NODE_ID_TIMEOUT)
#define CONFIG_BT_MAX_CONN MYNEWT_VAL(BLE_MAX_CONNECTIONS)
#define CONFIG_BT_MESH_SEQ_STORE_RATE MYNEWT_VAL(BLE_MESH_SEQ_STORE_RATE)
#define CONFIG_BT_MESH_RPL_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_RPL_STORE_TIMEOUT)
#define CONFIG_BT_MESH_APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)
#define CONFIG_BT_MESH_SUBNET_COUNT MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)
#define CONFIG_BT_MESH_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_STORE_TIMEOUT)
#define CONFIG_BT_MESH_IVU_DIVIDER MYNEWT_VAL(BLE_MESH_IVU_DIVIDER)
#define CONFIG_BT_DEVICE_NAME MYNEWT_VAL(BLE_MESH_DEVICE_NAME)
#define CONFIG_BT_MESH_TX_SEG_MAX MYNEWT_VAL(BLE_MESH_TX_SEG_MAX)
#define CONFIG_BT_MESH_LABEL_COUNT MYNEWT_VAL(BLE_MESH_LABEL_COUNT)
#define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_NODE_COUNT)
#define CONFIG_BT_MESH_LPN_GROUPS MYNEWT_VAL(BLE_MESH_LPN_GROUPS)
#define CONFIG_BT_MESH_ADV_BUF_COUNT MYNEWT_VAL(BLE_MESH_ADV_BUF_COUNT)
#define CONFIG_BT_MESH_SEG_BUFS MYNEWT_VAL(BLE_MESH_SEG_BUFS )
#define CONFIG_BT_MESH_FRIEND_QUEUE_SIZE MYNEWT_VAL(BLE_MESH_FRIEND_QUEUE_SIZE)
#define CONFIG_BT_MESH_FRIEND_RECV_WIN MYNEWT_VAL(BLE_MESH_FRIEND_RECV_WIN)
#define CONFIG_BT_MESH_LPN_POLL_TIMEOUT MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT)
#define CONFIG_BT_MESH_MODEL_GROUP_COUNT MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT)
#define CONFIG_BT_MESH_MODEL_KEY_COUNT MYNEWT_VAL(BLE_MESH_MODEL_KEY_COUNT)
#define CONFIG_BT_MESH_NODE_ID_TIMEOUT MYNEWT_VAL(BLE_MESH_NODE_ID_TIMEOUT)
#define CONFIG_BT_MAX_CONN MYNEWT_VAL(BLE_MAX_CONNECTIONS)
#define CONFIG_BT_MESH_SEQ_STORE_RATE MYNEWT_VAL(BLE_MESH_SEQ_STORE_RATE)
#define CONFIG_BT_MESH_RPL_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_RPL_STORE_TIMEOUT)
#define CONFIG_BT_MESH_APP_KEY_COUNT MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)
#define CONFIG_BT_MESH_SUBNET_COUNT MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)
#define CONFIG_BT_MESH_STORE_TIMEOUT MYNEWT_VAL(BLE_MESH_STORE_TIMEOUT)
#define CONFIG_BT_MESH_IVU_DIVIDER MYNEWT_VAL(BLE_MESH_IVU_DIVIDER)
#define CONFIG_BT_DEVICE_NAME MYNEWT_VAL(BLE_MESH_DEVICE_NAME)
#define CONFIG_BT_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX)
#define CONFIG_BT_MESH_TX_SEG_MAX MYNEWT_VAL(BLE_MESH_TX_SEG_MAX)
#define CONFIG_BT_MESH_RX_SEG_MAX MYNEWT_VAL(BLE_MESH_RX_SEG_MAX)
#define CONFIG_BT_MESH_RX_SEG_MSG_COUNT MYNEWT_VAL(BLE_MESH_RX_SEG_MSG_COUNT)
#define CONFIG_BT_MESH_LABEL_COUNT MYNEWT_VAL(BLE_MESH_LABEL_COUNT)
#define CONFIG_BT_MESH_NODE_COUNT MYNEWT_VAL(BLE_MESH_CDB_NODE_COUNT)
#define CONFIG_BT_GATT_PROXY_ENABLED MYNEWT_VAL(BLE_MESH_GATT_PROXY_ENABLED)
#define CONFIG_BT_MESH_DEFAULT_TTL MYNEWT_VAL(BLE_MESH_DEFAULT_TTL)
#define CONFIG_BT_MESH_NETWORK_TRANSMIT_COUNT MYNEWT_VAL(BLE_MESH_NETWORK_TRANSMIT_COUNT)
#define CONFIG_BT_MESH_NETWORK_TRANSMIT_INTERVAL MYNEWT_VAL(BLE_MESH_NETWORK_TRANSMIT_INTERVAL)
#define CONFIG_BT_MESH_RELAY_ENABLED MYNEWT_VAL(BLE_MESH_RELAY_ENABLED)
#define CONFIG_BT_MESH_RELAY_RETRANSMIT_INTERVAL MYNEWT_VAL(BLE_MESH_RELAY_RETRANSMIT_INTERVAL)
#define CONFIG_BT_MESH_BEACON_ENABLED MYNEWT_VAL(BLE_MESH_BEACON_ENABLED)
#define CONFIG_BT_MESH_FRIEND_ENABLED MYNEWT_VAL(BLE_MESH_FRIEND_ENABLED)
#define CONFIG_BT_MESH_RELAY MYNEWT_VAL(BLE_MESH_RELAY)
#define CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT MYNEWT_VAL(BLE_MESH_RELAY_RETRANSMIT_COUNT)
#define CONFIG_BT_MESH_GATT_PROXY_ENABLED MYNEWT_VAL(BLE_MESH_GATT_PROXY_ENABLED)
#define printk console_printf
@@ -437,7 +475,7 @@ static inline void k_sem_init(struct k_sem *sem, unsigned int initial_count,
ble_npl_sem_init(sem, initial_count);
}
static inline int k_sem_take(struct k_sem *sem, s32_t timeout)
static inline int k_sem_take(struct k_sem *sem, int32_t timeout)
{
uint32_t ticks;
@@ -459,8 +497,8 @@ static inline void k_sem_give(struct k_sem *sem)
static inline int net_buf_id(struct os_mbuf *buf)
{
struct os_mbuf_pool *pool = buf->om_omp;
u8_t *pool_start = (u8_t *)pool->omp_pool->mp_membuf_addr;
u8_t *buf_ptr = (u8_t *)buf;
uint8_t *pool_start = (uint8_t *)pool->omp_pool->mp_membuf_addr;
uint8_t *buf_ptr = (uint8_t *)buf;
return (buf_ptr - pool_start) / BUF_SIZE(pool);
}
@@ -506,6 +544,46 @@ settings_load(void)
#define BUILD_ASSERT(cond) _Static_assert(cond, "")
/* Memory slabs/blocks */
/** Memory slab structure */
struct k_mem_slab {
/**
* _wait_q_t is not required now, as we don't implement zephyr timeouts -
* if slab couldn't be allocated, we simply return error
*/
uint32_t num_blocks; /** number of memory blocks available for allocation */
size_t block_size; /** size of single block */
/**
* buffer for blocks - must be alligned to N-byte, where N is a power of 2.
* Minimal size of buffer is num_blocks * block_size
*/
char *buffer;
char *free_list; /** list of free memory blocks */
uint32_t num_used; /** count of used memory blocks */
};
struct k_mem_block_id {
uint32_t pool : 8;
uint32_t level : 4;
uint32_t block : 20;
};
struct k_mem_block {
void *data;
struct k_mem_block_id id;
};
extern void k_mem_slab_free(struct k_mem_slab *slab, void **mem);
extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem);
static inline uint32_t k_mem_slab_num_free_get(struct k_mem_slab *slab)
{
return slab->num_blocks - slab->num_used;
}
int create_free_list(struct k_mem_slab *slab);
#ifdef __cplusplus
}
#endif

View File

@@ -25,12 +25,12 @@ extern "C" {
struct bt_mesh_health_cli {
struct bt_mesh_model *model;
void (*current_status)(struct bt_mesh_health_cli *cli, u16_t addr,
u8_t test_id, u16_t cid, u8_t *faults,
void (*current_status)(struct bt_mesh_health_cli *cli, uint16_t addr,
uint8_t test_id, uint16_t cid, uint8_t *faults,
size_t fault_count);
struct k_sem op_sync;
u32_t op_pending;
uint32_t op_pending;
void *op_param;
};
@@ -43,32 +43,30 @@ extern const struct bt_mesh_model_cb bt_mesh_health_cli_cb;
int bt_mesh_health_cli_set(struct bt_mesh_model *model);
int bt_mesh_health_fault_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count);
int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid,
uint8_t *test_id, uint8_t *faults,
size_t *fault_count);
int bt_mesh_health_fault_clear(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count);
int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid,
uint8_t *test_id, uint8_t *faults,
size_t *fault_count);
int bt_mesh_health_fault_test(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t test_id, u8_t *faults,
size_t *fault_count);
int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid,
uint8_t test_id, uint8_t *faults,
size_t *fault_count);
int bt_mesh_health_period_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *divisor);
int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor);
int bt_mesh_health_period_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t divisor, u8_t *updated_divisor);
int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor,
uint8_t *updated_divisor);
int bt_mesh_health_attention_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *attention);
int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *attention);
int bt_mesh_health_attention_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t attention, u8_t *updated_attention);
int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attention,
uint8_t *updated_attention);
s32_t bt_mesh_health_cli_timeout_get(void);
void bt_mesh_health_cli_timeout_set(s32_t timeout);
int32_t bt_mesh_health_cli_timeout_get(void);
void bt_mesh_health_cli_timeout_set(int32_t timeout);
#ifdef __cplusplus
}

View File

@@ -23,21 +23,21 @@ extern "C" {
struct bt_mesh_health_srv_cb {
/* 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);
int (*fault_get_cur)(struct bt_mesh_model *model, uint8_t *test_id,
uint16_t *company_id, uint8_t *faults,
uint8_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);
int (*fault_get_reg)(struct bt_mesh_model *model, uint16_t company_id,
uint8_t *test_id, uint8_t *faults,
uint8_t *fault_count);
/* Clear registered faults */
int (*fault_clear)(struct bt_mesh_model *model, u16_t company_id);
int (*fault_clear)(struct bt_mesh_model *model, uint16_t company_id);
/* Run a specific test */
int (*fault_test)(struct bt_mesh_model *model, u8_t test_id,
u16_t company_id);
int (*fault_test)(struct bt_mesh_model *model, uint8_t test_id,
uint16_t company_id);
/* Attention on */
void (*attn_on)(struct bt_mesh_model *model);
@@ -52,7 +52,7 @@ struct bt_mesh_health_srv_cb {
*
* @param max_faults Maximum number of faults the element can have.
*
* @return a New net_buf_simple of the needed size.
* @return a New os_mbuf of the needed size.
*/
#define BT_MESH_HEALTH_FAULT_MSG(max_faults) \
NET_BUF_SIMPLE(1 + 3 + (max_faults))

View File

@@ -0,0 +1,123 @@
/** @file
* @brief Bluetooth Mesh Heartbeat API.
*/
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BLUETOOTH_MESH_HEARTBEAT_H_
#define _BLUETOOTH_MESH_HEARTBEAT_H_
/**
* @brief Bluetooth Mesh
* @defgroup bt_mesh_heartbeat Bluetooth Mesh Heartbeat
* @ingroup bt_mesh
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
/** Heartbeat Publication parameters */
struct bt_mesh_hb_pub {
/** Destination address. */
uint16_t dst;
/** Remaining publish count. */
uint16_t count;
/** Time To Live value. */
uint8_t ttl;
/**
* Bitmap of features that trigger a Heartbeat publication if
* they change. Legal values are @ref BT_MESH_FEAT_RELAY,
* @ref BT_MESH_FEAT_PROXY, @ref BT_MESH_FEAT_FRIEND and
* @ref BT_MESH_FEAT_LOW_POWER.
*/
uint16_t feat;
/** Network index used for publishing. */
uint16_t net_idx;
/** Publication period in seconds. */
uint32_t period;
};
/** Heartbeat Subscription parameters. */
struct bt_mesh_hb_sub {
/** Subscription period in seconds. */
uint32_t period;
/** Remaining subscription time in seconds. */
uint32_t remaining;
/** Source address to receive Heartbeats from. */
uint16_t src;
/** Destination address to received Heartbeats on. */
uint16_t dst;
/** The number of received Heartbeat messages so far. */
uint16_t count;
/**
* Minimum hops in received messages, ie the shortest registered
* path from the publishing node to the subscribing node. A
* Heartbeat received from an immediate neighbor has hop
* count = 1.
*/
uint8_t min_hops;
/**
* Maximum hops in received messages, ie the longest registered
* path from the publishing node to the subscribing node. A
* Heartbeat received from an immediate neighbor has hop
* count = 1.
*/
uint8_t max_hops;
};
/** Heartbeat callback structure */
struct bt_mesh_hb_cb {
/** @brief Receive callback for heartbeats.
*
* Gets called on every received Heartbeat that matches the current
* Heartbeat subscription parameters.
*
* @param sub Current Heartbeat subscription parameters.
* @param hops The number of hops the Heartbeat was received
* with.
* @param feat The feature set of the publishing node. The
* value is a bitmap of @ref BT_MESH_FEAT_RELAY,
* @ref BT_MESH_FEAT_PROXY,
* @ref BT_MESH_FEAT_FRIEND and
* @ref BT_MESH_FEAT_LOW_POWER.
*/
void (*recv)(const struct bt_mesh_hb_sub *sub, uint8_t hops,
uint16_t feat);
/** @brief Subscription end callback for heartbeats.
*
* Gets called when the subscription period ends, providing a summary
* of the received heartbeat messages.
*
* @param sub Current Heartbeat subscription parameters.
*/
void (*sub_end)(const struct bt_mesh_hb_sub *sub);
};
/** @brief Get the current Heartbeat publication parameters.
*
* @param get Heartbeat publication parameters return buffer.
*/
void bt_mesh_hb_pub_get(struct bt_mesh_hb_pub *get);
/** @brief Get the current Heartbeat subscription parameters.
*
* @param get Heartbeat subscription parameters return buffer.
*/
void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get);
extern struct bt_mesh_hb_cb hb_cb;
#ifdef __cplusplus
}
#endif
/**
* @}
*/
#endif /* _BLUETOOTH_MESH_HEARTBEAT_H_ */

View File

@@ -59,10 +59,37 @@ typedef enum {
BT_MESH_PROV_OOB_ON_DEV = BIT(15),
} bt_mesh_prov_oob_info_t;
/** Device Capabilities. */
struct bt_mesh_dev_capabilities {
/** Number of elements supported by the device */
uint8_t elem_count;
/** Supported algorithms and other capabilities */
uint16_t algorithms;
/** Supported public key types */
uint8_t pub_key_type;
/** Supported static OOB Types */
uint8_t static_oob;
/** Supported Output OOB Actions */
bt_mesh_output_action_t output_actions;
/** Supported Input OOB Actions */
bt_mesh_input_action_t input_actions;
/** Maximum size of Output OOB supported */
uint8_t output_size;
/** Maximum size in octets of Input OOB supported */
uint8_t input_size;
};
/** Provisioning properties & capabilities. */
struct bt_mesh_prov {
/** The UUID that's used when advertising as unprovisioned */
const u8_t *uuid;
const uint8_t *uuid;
/** Optional URI. This will be advertised separately from the
* unprovisioned beacon, however the unprovisioned beacon will
@@ -75,19 +102,34 @@ struct bt_mesh_prov {
bt_mesh_prov_oob_info_t oob_info;
/** Static OOB value */
const u8_t *static_val;
const uint8_t *static_val;
/** Static OOB value length */
u8_t static_val_len;
uint8_t static_val_len;
/** Maximum size of Output OOB supported */
u8_t output_size;
uint8_t output_size;
/** Supported Output OOB Actions */
u16_t output_actions;
uint16_t output_actions;
/* Maximum size of Input OOB supported */
u8_t input_size;
uint8_t input_size;
/** Supported Input OOB Actions */
u16_t input_actions;
uint16_t input_actions;
/** @brief Provisioning Capabilities.
*
* This callback notifies the application that the provisioning capabilities
* of the unprovisioned device has been received.
*
* The application can consequently call bt_mesh_auth_method_set_<*> to
* select suitable provisioning oob authentication method.
*
* When this callback returns, the provisioner will start authentication with
* the chosen method.
*
* @param cap capabilities supported by device.
*/
void (*capabilities)(const struct bt_mesh_dev_capabilities *cap);
/** @brief Output of a number is requested.
*
@@ -99,7 +141,7 @@ struct bt_mesh_prov {
*
* @return Zero on success or negative error code otherwise
*/
int (*output_number)(bt_mesh_output_action_t act, u32_t num);
int (*output_number)(bt_mesh_output_action_t act, uint32_t num);
/** @brief Output of a string is requested.
*
@@ -126,7 +168,7 @@ struct bt_mesh_prov {
*
* @return Zero on success or negative error code otherwise
*/
int (*input)(bt_mesh_input_action_t act, u8_t size);
int (*input)(bt_mesh_input_action_t act, uint8_t size);
/** @brief The other device finished their OOB input.
*
@@ -146,9 +188,9 @@ struct bt_mesh_prov {
* @param uri_hash Pointer to URI Hash value. NULL if no hash was
* present in the beacon.
*/
void (*unprovisioned_beacon)(u8_t uuid[16],
void (*unprovisioned_beacon)(uint8_t uuid[16],
bt_mesh_prov_oob_info_t oob_info,
u32_t *uri_hash);
uint32_t *uri_hash);
/** @brief Provisioning link has been opened.
*
@@ -177,7 +219,7 @@ struct bt_mesh_prov {
* @param net_idx NetKeyIndex given during provisioning.
* @param addr Primary element address.
*/
void (*complete)(u16_t net_idx, u16_t addr);
void (*complete)(uint16_t net_idx, uint16_t addr);
/** @brief A new node has been added to the provisioning database.
*
@@ -186,10 +228,12 @@ struct bt_mesh_prov {
* the specified NetKeyIndex and primary element address.
*
* @param net_idx NetKeyIndex given during provisioning.
* @param uuid UUID of the added node
* @param addr Primary element address.
* @param num_elem Number of elements that this node has.
*/
void (*node_added)(u16_t net_idx, u16_t addr, u8_t num_elem);
void (*node_added)(uint16_t net_idx, uint8_t uuid[16], uint16_t addr,
uint8_t num_elem);
/** @brief Node has been reset.
*
@@ -222,7 +266,90 @@ int bt_mesh_input_string(const char *str);
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_input_number(u32_t num);
int bt_mesh_input_number(uint32_t num);
/** @brief Provide Device public key.
*
* @param public_key Device public key.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64]);
/** @brief Use Input OOB authentication.
*
* Provisioner only.
*
* Instruct the unprovisioned device to use the specified Input OOB
* authentication action. When using @ref BT_MESH_PUSH, @ref BT_MESH_TWIST or
* @ref BT_MESH_ENTER_NUMBER, the @ref bt_mesh_prov::output_number callback is
* called with a random number that has to be entered on the unprovisioned
* device.
*
* When using @ref BT_MESH_ENTER_STRING, the @ref bt_mesh_prov::output_string
* callback is called with a random string that has to be entered on the
* unprovisioned device.
*
* @param action Authentication action used by the unprovisioned device.
* @param size Authentication size.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size);
/** @brief Use Output OOB authentication.
*
* Provisioner only.
*
* Instruct the unprovisioned device to use the specified Output OOB
* authentication action. The @ref bt_mesh_prov::input callback will
* be called.
*
* When using @ref BT_MESH_BLINK, @ref BT_MESH_BEEP, @ref BT_MESH_VIBRATE
* or @ref BT_MESH_DISPLAY_NUMBER, and the application has to call
* @ref bt_mesh_input_number with the random number indicated by
* the unprovisioned device.
*
* When using @ref BT_MESH_DISPLAY_STRING, the application has to call
* @ref bt_mesh_input_string with the random string displayed by the
* unprovisioned device.
*
* @param action Authentication action used by the unprovisioned device.
* @param size Authentication size.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_auth_method_set_output(bt_mesh_output_action_t action, uint8_t size);
/** @brief Use static OOB authentication.
*
* Provisioner only.
*
* Instruct the unprovisioned device to use static OOB authentication, and use
* the given static authentication value when provisioning.
*
* @param static_val Static OOB value.
* @param size Static OOB value size.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_auth_method_set_static(const uint8_t *static_val, uint8_t size);
/** @brief Don't use OOB authentication.
*
* Provisioner only.
*
* Don't use any authentication when provisioning new devices. This is the
* default behavior.
*
* @warning Not using any authentication exposes the mesh network to
* impersonation attacks, where attackers can pretend to be the
* unprovisioned device to gain access to the network. Authentication
* is strongly encouraged.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_auth_method_set_none(void);
/** @brief Enable specific provisioning bearers
*
@@ -258,25 +385,6 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers);
/* 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)
@@ -299,7 +407,7 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers);
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_init(u8_t own_addr_type,
int bt_mesh_init(uint8_t own_addr_type,
const struct bt_mesh_prov *prov,
const struct bt_mesh_comp *comp);
@@ -351,9 +459,9 @@ int bt_mesh_resume(void);
*
* @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, u16_t addr,
const u8_t dev_key[16]);
int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx,
uint8_t flags, uint32_t iv_index, uint16_t addr,
const uint8_t dev_key[16]);
/** @brief Provision a Mesh Node using PB-ADV
*
@@ -365,8 +473,8 @@ int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_provision_adv(const u8_t uuid[16], u16_t net_idx, u16_t addr,
u8_t attention_duration);
int bt_mesh_provision_adv(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
uint8_t attention_duration);
/** @brief Check if the local node has been provisioned.
*
@@ -428,7 +536,17 @@ int bt_mesh_lpn_poll(void);
*
* @param cb Function to call when the Friendship status changes.
*/
void bt_mesh_lpn_set_cb(void (*cb)(u16_t friend_addr, bool established));
void bt_mesh_lpn_set_cb(void (*cb)(uint16_t friend_addr, bool established));
/** @brief Terminate Friendship.
*
* Terminated Friendship for given LPN.
*
* @param lpn_addr Low Power Node address.
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_mesh_friend_terminate(uint16_t lpn_addr);
#ifdef __cplusplus
}

View File

@@ -17,10 +17,15 @@
#include "glue.h"
#include "access.h"
#include "main.h"
#include "cfg.h"
#include "cfg_srv.h"
#include "health_srv.h"
#include "cfg_cli.h"
#include "health_cli.h"
#include "proxy.h"
#include "cdb.h"
#include "cfg.h"
#include "heartbeat.h"
#include "../../src/app_keys.h"
#endif /* __BT_MESH_H */

View File

@@ -15,7 +15,7 @@ struct bt_mesh_gen_model_cli {
struct bt_mesh_model *model;
struct k_sem op_sync;
u32_t op_pending;
uint32_t op_pending;
void *op_param;
};
@@ -33,14 +33,14 @@ extern const struct bt_mesh_model_cb bt_mesh_gen_level_cli_cb;
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_LEVEL_CLI, gen_level_cli_op, pub,\
cli_data, &bt_mesh_gen_level_cli_cb)
int bt_mesh_gen_onoff_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *state);
int bt_mesh_gen_onoff_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t val, u8_t *state);
int bt_mesh_gen_level_get(u16_t net_idx, u16_t addr, u16_t app_idx,
s16_t *level);
int bt_mesh_gen_level_set(u16_t net_idx, u16_t addr, u16_t app_idx,
s16_t val, s16_t *state);
int bt_mesh_gen_onoff_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
uint8_t *state);
int bt_mesh_gen_onoff_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
uint8_t val, uint8_t *state);
int bt_mesh_gen_level_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
int16_t *level);
int bt_mesh_gen_level_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
int16_t val, int16_t *state);
#ifdef __cplusplus
}

View File

@@ -14,8 +14,8 @@ extern "C" {
struct bt_mesh_gen_onoff_srv {
struct bt_mesh_model *model;
int (*get)(struct bt_mesh_model *model, u8_t *state);
int (*set)(struct bt_mesh_model *model, u8_t state);
int (*get)(struct bt_mesh_model *model, uint8_t *state);
int (*set)(struct bt_mesh_model *model, uint8_t state);
};
extern const struct bt_mesh_model_op gen_onoff_srv_op[];
@@ -28,8 +28,8 @@ extern const struct bt_mesh_model_cb gen_onoff_srv_cb;
struct bt_mesh_gen_level_srv {
struct bt_mesh_model *model;
int (*get)(struct bt_mesh_model *model, s16_t *level);
int (*set)(struct bt_mesh_model *model, s16_t level);
int (*get)(struct bt_mesh_model *model, int16_t *level);
int (*set)(struct bt_mesh_model *model, int16_t level);
};
extern const struct bt_mesh_model_op gen_level_srv_op[];
@@ -42,8 +42,8 @@ extern const struct bt_mesh_model_cb gen_level_srv_cb;
struct bt_mesh_light_lightness_srv {
struct bt_mesh_model *model;
int (*get)(struct bt_mesh_model *model, s16_t *level);
int (*set)(struct bt_mesh_model *model, s16_t level);
int (*get)(struct bt_mesh_model *model, int16_t *level);
int (*set)(struct bt_mesh_model *model, int16_t level);
};
extern const struct bt_mesh_model_op light_lightness_srv_op[];
@@ -53,12 +53,12 @@ extern const struct bt_mesh_model_cb light_lightness_srv_cb;
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV, \
light_lightness_srv_op, pub, srv, &light_lightness_srv_cb)
void bt_mesh_set_gen_onoff_srv_cb(int (*get)(struct bt_mesh_model *model, u8_t *state),
int (*set)(struct bt_mesh_model *model, u8_t state));
void bt_mesh_set_gen_level_srv_cb(int (*get)(struct bt_mesh_model *model, s16_t *level),
int (*set)(struct bt_mesh_model *model, s16_t level));
void bt_mesh_set_light_lightness_srv_cb(int (*get)(struct bt_mesh_model *model, s16_t *level),
int (*set)(struct bt_mesh_model *model, s16_t level));
void bt_mesh_set_gen_onoff_srv_cb(int (*get)(struct bt_mesh_model *model, uint8_t *state),
int (*set)(struct bt_mesh_model *model, uint8_t state));
void bt_mesh_set_gen_level_srv_cb(int (*get)(struct bt_mesh_model *model, int16_t *level),
int (*set)(struct bt_mesh_model *model, int16_t level));
void bt_mesh_set_light_lightness_srv_cb(int (*get)(struct bt_mesh_model *model, int16_t *level),
int (*set)(struct bt_mesh_model *model, int16_t level));
#ifdef __cplusplus
}

View File

@@ -33,13 +33,13 @@ extern "C" {
* Allows access to Bluetooth stack internals, not exposed by public API.
*/
struct bt_test_cb {
void (*mesh_net_recv)(u8_t ttl, u8_t ctl, u16_t src, u16_t dst,
void (*mesh_net_recv)(uint8_t ttl, uint8_t ctl, uint16_t src, uint16_t dst,
const void *payload, size_t payload_len);
void (*mesh_model_bound)(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx);
void (*mesh_model_unbound)(u16_t addr, struct bt_mesh_model *model,
u16_t key_idx);
void (*mesh_prov_invalid_bearer)(u8_t opcode);
void (*mesh_model_bound)(uint16_t addr, struct bt_mesh_model *model,
uint16_t key_idx);
void (*mesh_model_unbound)(uint16_t addr, struct bt_mesh_model *model,
uint16_t key_idx);
void (*mesh_prov_invalid_bearer)(uint8_t opcode);
void (*mesh_trans_incomp_timer_exp)(void);
sys_snode_t node;
@@ -66,7 +66,7 @@ void bt_test_cb_unregister(struct bt_test_cb *cb);
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_test_mesh_lpn_group_add(u16_t group);
int bt_test_mesh_lpn_group_add(uint16_t group);
/** Send Friend Subscription List Remove message.
*
@@ -79,7 +79,7 @@ int bt_test_mesh_lpn_group_add(u16_t group);
*
* @return Zero on success or (negative) error code otherwise.
*/
int bt_test_mesh_lpn_group_remove(u16_t *groups, size_t groups_count);
int bt_test_mesh_lpn_group_remove(uint16_t *groups, size_t groups_count);
/** Clear replay protection list cache.
*
@@ -87,12 +87,12 @@ int bt_test_mesh_lpn_group_remove(u16_t *groups, size_t groups_count);
*/
int bt_test_mesh_rpl_clear(void);
u8_t mod_bind(struct bt_mesh_model *model, u16_t key_idx);
u8_t mod_unbind(struct bt_mesh_model *model, u16_t key_idx, bool store);
uint8_t mod_bind(struct bt_mesh_model *model, uint16_t key_idx);
uint8_t mod_unbind(struct bt_mesh_model *model, uint16_t key_idx, bool store);
int cmd_mesh_init(int argc, char *argv[]);
int bt_test_shell_init(void);
int bt_test_bind_app_key_to_model(struct bt_mesh_model *model, u16_t key_idx, u16_t id);
int bt_test_bind_app_key_to_model(struct bt_mesh_model *model, uint16_t key_idx, uint16_t id);
/**
* @}

View File

@@ -28,7 +28,7 @@
#endif
static const struct bt_mesh_comp *dev_comp;
static u16_t dev_primary_addr;
static uint16_t dev_primary_addr;
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem,
@@ -55,7 +55,7 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
}
}
s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
{
int period;
@@ -91,10 +91,10 @@ s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
}
}
static s32_t next_period(struct bt_mesh_model *mod)
static int32_t next_period(struct bt_mesh_model *mod)
{
struct bt_mesh_model_pub *pub = mod->pub;
u32_t elapsed, period;
uint32_t elapsed, period;
period = bt_mesh_model_pub_period_get(mod);
if (!period) {
@@ -117,7 +117,7 @@ static s32_t next_period(struct bt_mesh_model *mod)
static void publish_sent(int err, void *user_data)
{
struct bt_mesh_model *mod = user_data;
s32_t delay;
int32_t delay;
BT_DBG("err %d", err);
@@ -133,7 +133,7 @@ static void publish_sent(int err, void *user_data)
}
}
static void publish_start(u16_t duration, int err, void *user_data)
static void publish_start(uint16_t duration, int err, void *user_data)
{
struct bt_mesh_model *mod = user_data;
struct bt_mesh_model_pub *pub = mod->pub;
@@ -158,30 +158,18 @@ static int publish_retransmit(struct bt_mesh_model *mod)
{
struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_model_pub *pub = mod->pub;
struct bt_mesh_app_key *key;
struct bt_mesh_msg_ctx ctx = {
.addr = pub->addr,
.send_ttl = pub->ttl,
.app_idx = pub->key,
};
struct bt_mesh_net_tx tx = {
.ctx = &ctx,
.src = bt_mesh_model_elem(mod)->addr,
.xmit = bt_mesh_net_transmit_get(),
.friend_cred = pub->cred,
};
int err;
key = bt_mesh_app_key_find(pub->key);
if (!key) {
err = -EADDRNOTAVAIL;
goto done;
}
tx.sub = bt_mesh_subnet_get(key->net_idx);
ctx.net_idx = key->net_idx;
ctx.app_idx = key->app_idx;
net_buf_simple_init(sdu, 0);
net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len);
@@ -189,15 +177,22 @@ static int publish_retransmit(struct bt_mesh_model *mod)
err = bt_mesh_trans_send(&tx, sdu, &pub_sent_cb, mod);
done:
os_mbuf_free_chain(sdu);
return err;
}
static void publish_retransmit_end(int err, struct bt_mesh_model_pub *pub)
{
/* Cancel all retransmits for this publish attempt */
pub->count = 0U;
/* Make sure the publish timer gets reset */
publish_sent(err, pub->mod);
}
static void mod_publish(struct ble_npl_event *work)
{
struct bt_mesh_model_pub *pub = ble_npl_event_get_arg(work);
s32_t period_ms;
int32_t period_ms;
int err;
BT_DBG("");
@@ -229,7 +224,10 @@ static void mod_publish(struct ble_npl_event *work)
err = pub->update(pub->mod);
if (err) {
BT_ERR("Failed to update publication message");
/* Cancel this publish attempt. */
BT_DBG("Update failed, skipping publish (err: %d)", err);
pub->period_start = k_uptime_get_32();
publish_retransmit_end(err, pub);
return;
}
@@ -244,7 +242,7 @@ struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod)
return &dev_comp->elem[mod->elem_idx];
}
struct bt_mesh_model *bt_mesh_model_get(bool vnd, u8_t elem_idx, u8_t mod_idx)
struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx)
{
struct bt_mesh_elem *elem;
@@ -276,6 +274,11 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
bool vnd, bool primary, void *user_data)
{
int i;
int *err = user_data;
if (*err) {
return;
}
if (mod->pub) {
mod->pub->mod = mod;
@@ -295,12 +298,14 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
}
if (mod->cb && mod->cb->init) {
mod->cb->init(mod);
*err = mod->cb->init(mod);
}
}
int bt_mesh_comp_register(const struct bt_mesh_comp *comp)
{
int err;
/* There must be at least one element */
if (!comp->elem_count) {
return -EINVAL;
@@ -308,12 +313,13 @@ int bt_mesh_comp_register(const struct bt_mesh_comp *comp)
dev_comp = comp;
bt_mesh_model_foreach(mod_init, NULL);
err = 0;
bt_mesh_model_foreach(mod_init, &err);
return 0;
return err;
}
void bt_mesh_comp_provision(u16_t addr)
void bt_mesh_comp_provision(uint16_t addr)
{
int i;
@@ -336,16 +342,14 @@ 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)
uint16_t bt_mesh_primary_addr(void)
{
return dev_primary_addr;
}
static u16_t *model_group_get(struct bt_mesh_model *mod, u16_t addr)
static uint16_t *model_group_get(struct bt_mesh_model *mod, uint16_t addr)
{
int i;
@@ -359,13 +363,13 @@ static u16_t *model_group_get(struct bt_mesh_model *mod, u16_t addr)
}
struct find_group_visitor_ctx {
u16_t *entry;
uint16_t *entry;
struct bt_mesh_model *mod;
u16_t addr;
uint16_t addr;
};
static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod,
u32_t depth, void *user_data)
uint32_t depth, void *user_data)
{
struct find_group_visitor_ctx *ctx = user_data;
@@ -382,7 +386,7 @@ static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod,
return BT_MESH_WALK_CONTINUE;
}
u16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, u16_t addr)
uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr)
{
struct find_group_visitor_ctx ctx = {
.mod = *mod,
@@ -398,10 +402,10 @@ u16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, u16_t addr)
}
static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
u16_t group_addr)
uint16_t group_addr)
{
struct bt_mesh_model *model;
u16_t *match;
uint16_t *match;
int i;
for (i = 0; i < elem->model_count; i++) {
@@ -425,9 +429,9 @@ static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
return NULL;
}
struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr)
struct bt_mesh_elem *bt_mesh_elem_find(uint16_t addr)
{
u16_t index;
uint16_t index;
if (BT_MESH_ADDR_IS_UNICAST(addr)) {
index = (addr - dev_comp->elem[0].addr);
@@ -449,12 +453,12 @@ struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr)
return NULL;
}
u8_t bt_mesh_elem_count(void)
uint8_t bt_mesh_elem_count(void)
{
return dev_comp->elem_count;
}
static bool model_has_key(struct bt_mesh_model *mod, u16_t key)
static bool model_has_key(struct bt_mesh_model *mod, uint16_t key)
{
int i;
@@ -469,22 +473,26 @@ static bool model_has_key(struct bt_mesh_model *mod, u16_t key)
return false;
}
static bool model_has_dst(struct bt_mesh_model *mod, u16_t dst)
static bool model_has_dst(struct bt_mesh_model *mod, uint16_t dst)
{
if (BT_MESH_ADDR_IS_UNICAST(dst)) {
return (dev_comp->elem[mod->elem_idx].addr == dst);
} else if (BT_MESH_ADDR_IS_GROUP(dst) || BT_MESH_ADDR_IS_VIRTUAL(dst)) {
return bt_mesh_model_find_group(&mod, dst);
return !!bt_mesh_model_find_group(&mod, dst);
}
return (mod->elem_idx == 0 && bt_mesh_fixed_group_match(dst));
/* If a message with a fixed group address is sent to the access layer,
* the lower layers have already confirmed that we are subscribing to
* it. All models on the primary element should receive the message.
*/
return mod->elem_idx == 0;
}
static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models,
u8_t model_count, u32_t opcode,
uint8_t model_count, uint32_t opcode,
struct bt_mesh_model **model)
{
u8_t i;
uint8_t i;
for (i = 0; i < model_count; i++) {
const struct bt_mesh_model_op *op;
@@ -502,7 +510,7 @@ static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models,
return NULL;
}
static int get_opcode(struct os_mbuf *buf, u32_t *opcode)
static int get_opcode(struct os_mbuf *buf, uint32_t *opcode)
{
switch (buf->om_data[0] >> 6) {
case 0x00:
@@ -529,6 +537,10 @@ static int get_opcode(struct os_mbuf *buf, u32_t *opcode)
}
*opcode = net_buf_simple_pull_u8(buf) << 16;
/* Using LE for the CID since the model layer is defined as
* little-endian in the mesh spec and using BT_MESH_MODEL_OP_3
* will declare the opcode in this way.
*/
*opcode |= net_buf_simple_pull_le16(buf);
return 0;
}
@@ -536,29 +548,12 @@ static int get_opcode(struct os_mbuf *buf, u32_t *opcode)
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:
return (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
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;
uint32_t opcode;
uint8_t count;
int i;
BT_DBG("app_idx 0x%04x src 0x%04x dst 0x%04x", rx->ctx.app_idx,
@@ -617,7 +612,7 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
}
}
void bt_mesh_model_msg_init(struct os_mbuf *msg, u32_t opcode)
void bt_mesh_model_msg_init(struct os_mbuf *msg, uint32_t opcode)
{
net_buf_simple_init(msg, 0);
@@ -630,6 +625,10 @@ void bt_mesh_model_msg_init(struct os_mbuf *msg, u32_t opcode)
break;
case 3:
net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff));
/* Using LE for the CID since the model layer is defined as
* little-endian in the mesh spec and using BT_MESH_MODEL_OP_3
* will declare the opcode in this way.
*/
net_buf_simple_add_le16(msg, opcode & 0xffff);
break;
default:
@@ -676,11 +675,8 @@ int bt_mesh_model_send(struct bt_mesh_model *model,
const struct bt_mesh_send_cb *cb, void *cb_data)
{
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(ctx->net_idx),
.ctx = ctx,
.src = bt_mesh_model_elem(model)->addr,
.xmit = bt_mesh_net_transmit_get(),
.friend_cred = 0,
};
return model_send(model, &tx, false, msg, cb, cb_data);
@@ -690,13 +686,15 @@ int bt_mesh_model_publish(struct bt_mesh_model *model)
{
struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_model_pub *pub = model->pub;
struct bt_mesh_app_key *key;
struct bt_mesh_msg_ctx ctx = {
.addr = pub->addr,
.send_ttl = pub->ttl,
.send_rel = pub->send_rel,
.app_idx = pub->key,
};
struct bt_mesh_net_tx tx = {
.ctx = &ctx,
.src = bt_mesh_model_elem(model)->addr,
.xmit = bt_mesh_net_transmit_get(),
};
int err;
@@ -712,12 +710,6 @@ int bt_mesh_model_publish(struct bt_mesh_model *model)
goto done;
}
key = bt_mesh_app_key_find(pub->key);
if (!key) {
err = -EADDRNOTAVAIL;
goto done;
}
if (pub->msg->om_len + 4 > BT_MESH_TX_SDU_MAX) {
BT_ERR("Message does not fit maximum SDU size");
err = -EMSGSIZE;
@@ -732,13 +724,7 @@ int bt_mesh_model_publish(struct bt_mesh_model *model)
net_buf_simple_init(sdu, 0);
net_buf_simple_add_mem(sdu, pub->msg->om_data, pub->msg->om_len);
ctx.addr = pub->addr;
ctx.send_ttl = pub->ttl;
ctx.net_idx = key->net_idx;
ctx.app_idx = key->app_idx;
tx.friend_cred = pub->cred;
tx.sub = bt_mesh_subnet_get(ctx.net_idx),
pub->count = BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit);
@@ -747,10 +733,7 @@ int bt_mesh_model_publish(struct bt_mesh_model *model)
err = model_send(model, &tx, true, sdu, &pub_sent_cb, model);
if (err) {
/* Don't try retransmissions for this publish attempt */
pub->count = 0;
/* Make sure the publish timer gets reset */
publish_sent(err, model);
publish_retransmit_end(err, pub);
}
done:
@@ -759,9 +742,9 @@ done:
}
struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem,
u16_t company, u16_t id)
uint16_t company, uint16_t id)
{
u8_t i;
uint8_t i;
for (i = 0; i < elem->vnd_model_count; i++) {
if (elem->vnd_models[i].vnd.company == company &&
@@ -774,9 +757,9 @@ struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem,
}
struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem,
u16_t id)
uint16_t id)
{
u8_t i;
uint8_t i;
for (i = 0; i < elem->model_count; i++) {
if (elem->models[i].id == id) {
@@ -804,29 +787,38 @@ struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod)
void bt_mesh_model_tree_walk(struct bt_mesh_model *root,
enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod,
u32_t depth,
uint32_t depth,
void *user_data),
void *user_data)
{
struct bt_mesh_model *m = root;
u32_t depth = 0;
int depth = 0;
/* 'skip' is set to true when we ascend from child to parent node.
* In that case, we want to skip calling the callback on the parent
* node and we don't want to descend onto a child node as those
* nodes have already been visited.
*/
bool skip = false;
do {
if (cb(m, depth, user_data) == BT_MESH_WALK_STOP) {
if (!skip &&
cb(m, (uint32_t)depth, user_data) == BT_MESH_WALK_STOP) {
return;
}
#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS)
if (m->extends) {
if (!skip && m->extends) {
m = m->extends;
depth++;
} else if (m->flags & BT_MESH_MOD_NEXT_IS_PARENT) {
m = m->next->next;
m = m->next;
depth--;
skip = true;
} else {
m = m->next;
skip = false;
}
#endif
} while (m && m != root);
} while (m && depth > 0);
}
#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS)

View File

@@ -16,8 +16,7 @@ enum {
BT_MESH_MOD_BIND_PENDING = BIT(0),
BT_MESH_MOD_SUB_PENDING = BIT(1),
BT_MESH_MOD_PUB_PENDING = BIT(2),
BT_MESH_MOD_DATA_PRESENT = BIT(3),
BT_MESH_MOD_NEXT_IS_PARENT = BIT(4),
BT_MESH_MOD_NEXT_IS_PARENT = BIT(3),
};
/* Tree walk return codes */
@@ -26,23 +25,21 @@ enum bt_mesh_walk {
BT_MESH_WALK_CONTINUE,
};
void bt_mesh_elem_register(struct bt_mesh_elem *elem, u8_t count);
void bt_mesh_elem_register(struct bt_mesh_elem *elem, uint8_t count);
u8_t bt_mesh_elem_count(void);
uint8_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_elem *bt_mesh_elem_find(uint16_t addr);
struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod);
void bt_mesh_model_tree_walk(struct bt_mesh_model *root,
enum bt_mesh_walk (*cb)(struct bt_mesh_model *mod,
u32_t depth,
uint32_t depth,
void *user_data),
void *user_data);
u16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, u16_t addr);
bool bt_mesh_fixed_group_match(u16_t addr);
uint16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, uint16_t addr);
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem,
@@ -50,16 +47,16 @@ void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
void *user_data),
void *user_data);
s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod);
int32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod);
void bt_mesh_comp_provision(u16_t addr);
void bt_mesh_comp_provision(uint16_t addr);
void bt_mesh_comp_unprovision(void);
u16_t bt_mesh_primary_addr(void);
uint16_t bt_mesh_primary_addr(void);
const struct bt_mesh_comp *bt_mesh_comp_get(void);
struct bt_mesh_model *bt_mesh_model_get(bool vnd, u8_t elem_idx, u8_t mod_idx);
struct bt_mesh_model *bt_mesh_model_get(bool vnd, uint8_t elem_idx, uint8_t mod_idx);
void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);

View File

@@ -40,21 +40,20 @@
#define ADV_INT_DEFAULT_MS 100
#define ADV_INT_FAST_MS 20
static s32_t adv_int_min = ADV_INT_DEFAULT_MS;
static int32_t adv_int_min = ADV_INT_DEFAULT_MS;
/* TinyCrypt PRNG consumes a lot of stack space, so we need to have
* an increased call stack whenever it's used.
*/
#if MYNEWT
#define ADV_STACK_SIZE 768
OS_TASK_STACK_DEFINE(g_blemesh_stack, ADV_STACK_SIZE);
OS_TASK_STACK_DEFINE(g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE));
struct os_task adv_task;
#else
static TaskHandle_t adv_task_h;
#endif
static struct ble_npl_eventq adv_queue;
extern u8_t g_mesh_addr_type;
extern uint8_t g_mesh_addr_type;
static int adv_initialized = false;
static os_membuf_t adv_buf_mem[OS_MEMPOOL_SIZE(
@@ -64,14 +63,6 @@ static os_membuf_t adv_buf_mem[OS_MEMPOOL_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,
[BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI,
};
static struct bt_mesh_adv adv_pool[CONFIG_BT_MESH_ADV_BUF_COUNT];
static struct bt_mesh_adv *adv_alloc(int id)
@@ -79,7 +70,7 @@ static struct bt_mesh_adv *adv_alloc(int id)
return &adv_pool[id];
}
static inline void adv_send_start(u16_t duration, int err,
static inline void adv_send_start(uint16_t duration, int err,
const struct bt_mesh_send_cb *cb,
void *cb_data)
{
@@ -98,10 +89,17 @@ static inline void adv_send_end(int err, const struct bt_mesh_send_cb *cb,
static inline void adv_send(struct os_mbuf *buf)
{
static const uint8_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,
[BT_MESH_ADV_URI] = BLE_HS_ADV_TYPE_URI,
} ;
const struct bt_mesh_send_cb *cb = BT_MESH_ADV(buf)->cb;
void *cb_data = BT_MESH_ADV(buf)->cb_data;
struct ble_gap_adv_params param = { 0 };
u16_t duration, adv_int;
uint16_t duration, adv_int;
struct bt_data ad;
int err;
@@ -158,7 +156,7 @@ mesh_adv_thread(void *args)
static struct ble_npl_event *ev;
struct os_mbuf *buf;
#if (MYNEWT_VAL(BLE_MESH_PROXY))
s32_t timeout;
int32_t timeout;
#endif
BT_DBG("started");
@@ -212,7 +210,7 @@ void bt_mesh_adv_update(void)
struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
bt_mesh_adv_alloc_t get_id,
enum bt_mesh_adv_type type,
u8_t xmit, s32_t timeout)
uint8_t xmit, int32_t timeout)
{
struct bt_mesh_adv *adv;
struct os_mbuf *buf;
@@ -241,8 +239,8 @@ struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
return buf;
}
struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, u8_t xmit,
s32_t timeout)
struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit,
int32_t timeout)
{
return bt_mesh_adv_create_from_pool(&adv_os_mbuf_pool, adv_alloc, type,
xmit, timeout);
@@ -261,8 +259,8 @@ void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
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)
static void bt_mesh_scan_cb(const bt_addr_le_t *addr, int8_t rssi,
uint8_t adv_type, struct os_mbuf *buf)
{
if (adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
return;
@@ -274,7 +272,7 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, s8_t rssi,
while (buf->om_len > 1) {
struct net_buf_simple_state state;
u8_t len, type;
uint8_t len, type;
len = net_buf_simple_pull_u8(buf);
/* Check for early termination */
@@ -308,7 +306,7 @@ static void bt_mesh_scan_cb(const bt_addr_le_t *addr, s8_t rssi,
}
net_buf_simple_restore(buf, &state);
net_buf_simple_pull(buf, len);
net_buf_simple_pull_mem(buf, len);
}
}
@@ -337,7 +335,7 @@ void bt_mesh_adv_init(void)
#if MYNEWT
os_task_init(&adv_task, "mesh_adv", mesh_adv_thread, NULL,
MYNEWT_VAL(BLE_MESH_ADV_TASK_PRIO), OS_WAIT_FOREVER,
g_blemesh_stack, ADV_STACK_SIZE);
g_blemesh_stack, MYNEWT_VAL(BLE_MESH_ADV_STACK_SIZE));
#elif ESP_PLATFORM
xTaskCreatePinnedToCore(mesh_adv_thread, "mesh_adv", 2768,
NULL, (configMAX_PRIORITIES - 5), &adv_task_h, NIMBLE_CORE);

View File

@@ -31,23 +31,18 @@ enum bt_mesh_adv_type
BT_MESH_ADV_URI,
};
typedef void (*bt_mesh_adv_func_t)(struct os_mbuf *buf, u16_t duration,
typedef void (*bt_mesh_adv_func_t)(struct os_mbuf *buf, uint16_t duration,
int err, void *user_data);
struct bt_mesh_adv {
const struct bt_mesh_send_cb *cb;
void *cb_data;
u8_t type:2,
uint8_t type:2,
busy:1;
u8_t xmit;
uint8_t xmit;
/* For transport layer segment sending */
struct {
u8_t attempts;
} seg;
u8_t flags;
uint8_t flags;
int ref_cnt;
struct ble_npl_event ev;
@@ -56,13 +51,13 @@ struct bt_mesh_adv {
typedef struct bt_mesh_adv *(*bt_mesh_adv_alloc_t)(int id);
/* 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,
s32_t timeout);
struct os_mbuf *bt_mesh_adv_create(enum bt_mesh_adv_type type, uint8_t xmit,
int32_t timeout);
struct os_mbuf *bt_mesh_adv_create_from_pool(struct os_mbuf_pool *pool,
bt_mesh_adv_alloc_t get_id,
enum bt_mesh_adv_type type,
u8_t xmit, s32_t timeout);
uint8_t xmit, int32_t timeout);
void bt_mesh_adv_send(struct os_mbuf *buf, const struct bt_mesh_send_cb *cb,
void *cb_data);

View File

@@ -0,0 +1,229 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#include "crypto.h"
#define MESH_LOG_MODULE BLE_MESH_LOG
static inline void xor16(uint8_t *dst, const uint8_t *a, const uint8_t *b)
{
dst[0] = a[0] ^ b[0];
dst[1] = a[1] ^ b[1];
dst[2] = a[2] ^ b[2];
dst[3] = a[3] ^ b[3];
dst[4] = a[4] ^ b[4];
dst[5] = a[5] ^ b[5];
dst[6] = a[6] ^ b[6];
dst[7] = a[7] ^ b[7];
dst[8] = a[8] ^ b[8];
dst[9] = a[9] ^ b[9];
dst[10] = a[10] ^ b[10];
dst[11] = a[11] ^ b[11];
dst[12] = a[12] ^ b[12];
dst[13] = a[13] ^ b[13];
dst[14] = a[14] ^ b[14];
dst[15] = a[15] ^ b[15];
}
/* pmsg is assumed to have the nonce already present in bytes 1-13 */
static int ccm_calculate_X0(const uint8_t key[16], const uint8_t *aad, uint8_t aad_len,
size_t mic_size, uint8_t msg_len, uint8_t b[16],
uint8_t X0[16])
{
int i, j, err;
/* X_0 = e(AppKey, flags || nonce || length) */
b[0] = (((mic_size - 2) / 2) << 3) | ((!!aad_len) << 6) | 0x01;
sys_put_be16(msg_len, b + 14);
err = bt_encrypt_be(key, b, X0);
if (err) {
return err;
}
/* If AAD is being used to authenticate, include it here */
if (aad_len) {
sys_put_be16(aad_len, b);
for (i = 0; i < sizeof(uint16_t); i++) {
b[i] = X0[i] ^ b[i];
}
j = 0;
aad_len += sizeof(uint16_t);
while (aad_len > 16) {
do {
b[i] = X0[i] ^ aad[j];
i++, j++;
} while (i < 16);
aad_len -= 16;
i = 0;
err = bt_encrypt_be(key, b, X0);
if (err) {
return err;
}
}
for (; i < aad_len; i++, j++) {
b[i] = X0[i] ^ aad[j];
}
for (i = aad_len; i < 16; i++) {
b[i] = X0[i];
}
err = bt_encrypt_be(key, b, X0);
if (err) {
return err;
}
}
return 0;
}
static int ccm_auth(const uint8_t key[16], uint8_t nonce[13],
const uint8_t *cleartext_msg, size_t msg_len, const uint8_t *aad,
size_t aad_len, uint8_t *mic, size_t mic_size)
{
uint8_t b[16], Xn[16], s0[16];
uint16_t blk_cnt, last_blk;
int err, j, i;
last_blk = msg_len % 16;
blk_cnt = (msg_len + 15) / 16;
if (!last_blk) {
last_blk = 16U;
}
b[0] = 0x01;
memcpy(b + 1, nonce, 13);
/* S[0] = e(AppKey, 0x01 || nonce || 0x0000) */
sys_put_be16(0x0000, &b[14]);
err = bt_encrypt_be(key, b, s0);
if (err) {
return err;
}
ccm_calculate_X0(key, aad, aad_len, mic_size, msg_len, b, Xn);
for (j = 0; j < blk_cnt; j++) {
/* X_1 = e(AppKey, X_0 ^ Payload[0-15]) */
if (j + 1 == blk_cnt) {
for (i = 0; i < last_blk; i++) {
b[i] = Xn[i] ^ cleartext_msg[(j * 16) + i];
}
memcpy(&b[i], &Xn[i], 16 - i);
} else {
xor16(b, Xn, &cleartext_msg[j * 16]);
}
err = bt_encrypt_be(key, b, Xn);
if (err) {
return err;
}
}
/* MIC = C_mic ^ X_1 */
for (i = 0; i < mic_size; i++) {
mic[i] = s0[i] ^ Xn[i];
}
return 0;
}
static int ccm_crypt(const uint8_t key[16], const uint8_t nonce[13],
const uint8_t *in_msg, uint8_t *out_msg, size_t msg_len)
{
uint8_t a_i[16], s_i[16];
uint16_t last_blk, blk_cnt;
size_t i, j;
int err;
last_blk = msg_len % 16;
blk_cnt = (msg_len + 15) / 16;
if (!last_blk) {
last_blk = 16U;
}
a_i[0] = 0x01;
memcpy(&a_i[1], nonce, 13);
for (j = 0; j < blk_cnt; j++) {
/* S_1 = e(AppKey, 0x01 || nonce || 0x0001) */
sys_put_be16(j + 1, &a_i[14]);
err = bt_encrypt_be(key, a_i, s_i);
if (err) {
return err;
}
/* Encrypted = Payload[0-15] ^ C_1 */
if (j < blk_cnt - 1) {
xor16(&out_msg[j * 16], s_i, &in_msg[j * 16]);
} else {
for (i = 0; i < last_blk; i++) {
out_msg[(j * 16) + i] =
in_msg[(j * 16) + i] ^ s_i[i];
}
}
}
return 0;
}
int bt_ccm_decrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *enc_msg,
size_t msg_len, const uint8_t *aad, size_t aad_len,
uint8_t *out_msg, size_t mic_size)
{
uint8_t mic[16];
if (aad_len >= 0xff00 || mic_size > sizeof(mic)) {
return -EINVAL;
}
ccm_crypt(key, nonce, enc_msg, out_msg, msg_len);
ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size);
if (memcmp(mic, enc_msg + msg_len, mic_size)) {
return -EBADMSG;
}
return 0;
}
int bt_ccm_encrypt(const uint8_t key[16], uint8_t nonce[13], const uint8_t *msg,
size_t msg_len, const uint8_t *aad, size_t aad_len,
uint8_t *out_msg, size_t mic_size)
{
uint8_t *mic = out_msg + msg_len;
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 || mic_size > 16) {
return -EINVAL;
}
ccm_auth(key, nonce, out_msg, msg_len, aad, aad_len, mic, mic_size);
ccm_crypt(key, nonce, msg, out_msg, msg_len);
return 0;
}
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,512 @@
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#include <string.h>
#include <stdlib.h>
#include "../include/mesh/mesh.h"
#include "mesh_priv.h"
#include "net.h"
#include "app_keys.h"
#include "rpl.h"
#include "settings.h"
#include "crypto.h"
#include "adv.h"
#include "proxy.h"
#include "friend.h"
#include "foundation.h"
#include "access.h"
#include "subnet.h"
#define MESH_LOG_MODULE BLE_MESH_LOG
#include "nimble/porting/nimble/include/log/log.h"
static struct bt_mesh_app_key apps[CONFIG_BT_MESH_APP_KEY_COUNT] = {
[0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = {
.app_idx = BT_MESH_KEY_UNUSED,
.net_idx = BT_MESH_KEY_UNUSED,
}
};
static void app_key_evt(struct bt_mesh_app_key *app, enum bt_mesh_key_evt evt)
{
int i;
for (i = 0; i < (sizeof(bt_mesh_app_key_cb_list)/sizeof(void *)); i++) {
if (bt_mesh_app_key_cb_list[i]) {
BT_DBG("app_key_evt %d", i);
bt_mesh_app_key_cb_list[i] (app->app_idx, app->net_idx, evt);
}
}
}
struct bt_mesh_app_key *app_get(uint16_t app_idx)
{
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
if (apps[i].app_idx == app_idx) {
return &apps[i];
}
}
return NULL;
}
static struct bt_mesh_app_key *app_key_alloc(uint16_t app_idx)
{
struct bt_mesh_app_key *app = NULL;
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
/* Check for already existing app_key */
if (apps[i].app_idx == app_idx) {
return &apps[i];
}
if (!app && apps[i].app_idx == BT_MESH_KEY_UNUSED) {
app = &apps[i];
}
}
return app;
}
static void app_key_del(struct bt_mesh_app_key *app)
{
BT_DBG("AppIdx 0x%03x", app->app_idx);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_clear_app_key(app->app_idx);
}
app_key_evt(app, BT_MESH_KEY_DELETED);
app->net_idx = BT_MESH_KEY_UNUSED;
app->app_idx = BT_MESH_KEY_UNUSED;
(void)memset(app->keys, 0, sizeof(app->keys));
}
static void app_key_revoke(struct bt_mesh_app_key *app)
{
if (!app->updated) {
return;
}
memcpy(&app->keys[0], &app->keys[1], sizeof(app->keys[0]));
memset(&app->keys[1], 0, sizeof(app->keys[1]));
app->updated = false;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_app_key(app->app_idx);
}
app_key_evt(app, BT_MESH_KEY_REVOKED);
}
static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
{
if (evt == BT_MESH_KEY_UPDATED || evt == BT_MESH_KEY_ADDED) {
return;
}
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
struct bt_mesh_app_key *app = &apps[i];
if (app->app_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (app->net_idx != sub->net_idx) {
continue;
}
if (evt == BT_MESH_KEY_DELETED) {
app_key_del(app);
} else if (evt == BT_MESH_KEY_REVOKED) {
app_key_revoke(app);
} else if (evt == BT_MESH_KEY_SWAPPED && app->updated) {
app_key_evt(app, BT_MESH_KEY_SWAPPED);
}
}
}
uint8_t bt_mesh_app_key_add(uint16_t app_idx, uint16_t net_idx,
const uint8_t key[16])
{
if (!bt_mesh_subnet_cb_list[0]) {
bt_mesh_subnet_cb_list[0] = subnet_evt;
}
struct bt_mesh_app_key *app;
BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx,
bt_hex(key, 16));
if (!bt_mesh_subnet_get(net_idx)) {
return STATUS_INVALID_NETKEY;
}
app = app_key_alloc(app_idx);
if (!app) {
return STATUS_INSUFF_RESOURCES;
}
if (app->app_idx == app_idx) {
if (app->net_idx != net_idx) {
return STATUS_INVALID_BINDING;
}
if (memcmp(key, app->keys[0].val, 16)) {
return STATUS_IDX_ALREADY_STORED;
}
return STATUS_SUCCESS;
}
if (bt_mesh_app_id(key, &app->keys[0].id)) {
return STATUS_CANNOT_SET;
}
BT_DBG("AppIdx 0x%04x AID 0x%02x", app_idx, app->keys[0].id);
app->net_idx = net_idx;
app->app_idx = app_idx;
app->updated = false;
memcpy(app->keys[0].val, key, 16);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
BT_DBG("Storing AppKey persistently");
bt_mesh_store_app_key(app->app_idx);
}
app_key_evt(app, BT_MESH_KEY_ADDED);
return STATUS_SUCCESS;
}
struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx)
{
struct bt_mesh_app_key *app;
app = app_get(app_idx);
if (app) {
return app;
}
return NULL;
}
uint8_t bt_mesh_app_key_update(uint16_t app_idx, uint16_t net_idx,
const uint8_t key[16])
{
struct bt_mesh_app_key *app;
struct bt_mesh_subnet *sub;
BT_DBG("net_idx 0x%04x app_idx %04x val %s", net_idx, app_idx,
bt_hex(key, 16));
app = app_get(app_idx);
if (!app) {
return STATUS_INVALID_APPKEY;
}
if (net_idx != BT_MESH_KEY_UNUSED && app->net_idx != net_idx) {
return STATUS_INVALID_BINDING;
}
sub = bt_mesh_subnet_get(app->net_idx);
if (!sub) {
return STATUS_INVALID_NETKEY;
}
/* The AppKey Update message shall generate an error when node
* is in normal operation, Phase 2, or Phase 3 or in Phase 1
* when the AppKey Update message on a valid AppKeyIndex when
* the AppKey value is different.
*/
if (sub->kr_phase != BT_MESH_KR_PHASE_1) {
return STATUS_CANNOT_UPDATE;
}
if (app->updated) {
if (memcmp(app->keys[1].val, key, 16)) {
return STATUS_IDX_ALREADY_STORED;
}
return STATUS_SUCCESS;
}
if (bt_mesh_app_id(key, &app->keys[1].id)) {
return STATUS_CANNOT_UPDATE;
}
BT_DBG("app_idx 0x%04x AID 0x%02x", app_idx, app->keys[1].id);
app->updated = true;
memcpy(app->keys[1].val, key, 16);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
BT_DBG("Storing AppKey persistently");
bt_mesh_store_app_key(app->app_idx);
}
app_key_evt(app, BT_MESH_KEY_UPDATED);
return STATUS_SUCCESS;
}
uint8_t bt_mesh_app_key_del(uint16_t app_idx, uint16_t net_idx)
{
struct bt_mesh_app_key *app;
BT_DBG("AppIdx 0x%03x", app_idx);
if (net_idx != BT_MESH_KEY_UNUSED && !bt_mesh_subnet_get(net_idx)) {
return STATUS_INVALID_NETKEY;
}
app = app_get(app_idx);
if (!app) {
/* This could be a retry of a previous attempt that had its
* response lost, so pretend that it was a success.
*/
return STATUS_SUCCESS;
}
if (net_idx != BT_MESH_KEY_UNUSED && net_idx != app->net_idx) {
return STATUS_INVALID_BINDING;
}
app_key_del(app);
return STATUS_SUCCESS;
}
int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx,
const uint8_t old_key[16], const uint8_t new_key[16])
{
struct bt_mesh_app_key *app;
app = app_key_alloc(app_idx);
if (!app) {
return -ENOMEM;
}
if (app->app_idx == app_idx) {
return 0;
}
BT_DBG("AppIdx 0x%04x AID 0x%02x", app_idx, app->keys[0].id);
memcpy(app->keys[0].val, old_key, 16);
if (bt_mesh_app_id(old_key, &app->keys[0].id)) {
return -EIO;
}
if (new_key) {
memcpy(app->keys[1].val, new_key, 16);
if (bt_mesh_app_id(new_key, &app->keys[1].id)) {
return -EIO;
}
}
app->net_idx = net_idx;
app->app_idx = app_idx;
app->updated = !!new_key;
return 0;
}
bool bt_mesh_app_key_exists(uint16_t app_idx)
{
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
if (apps[i].app_idx == app_idx) {
return true;
}
}
return false;
}
ssize_t bt_mesh_app_keys_get(uint16_t net_idx, uint16_t app_idxs[], size_t max,
off_t skip)
{
size_t count = 0;
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
struct bt_mesh_app_key *app = &apps[i];
if (app->app_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (net_idx != BT_MESH_KEY_ANY && app->net_idx != net_idx) {
continue;
}
if (skip) {
skip--;
continue;
}
if (count >= max) {
return -ENOMEM;
}
app_idxs[count++] = app->app_idx;
}
return count;
}
int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx,
struct bt_mesh_subnet **sub,
const uint8_t **app_key, uint8_t *aid)
{
struct bt_mesh_app_key *app = NULL;
if (BT_MESH_IS_DEV_KEY(ctx->app_idx)) {
/* With device keys, the application has to decide which subnet
* to send on.
*/
*sub = bt_mesh_subnet_get(ctx->net_idx);
if (!*sub) {
BT_WARN("Unknown NetKey 0x%03x", ctx->net_idx);
return -EINVAL;
}
if (ctx->app_idx == BT_MESH_KEY_DEV_REMOTE &&
!bt_mesh_elem_find(ctx->addr)) {
struct bt_mesh_cdb_node *node;
if (!IS_ENABLED(CONFIG_BT_MESH_CDB)) {
BT_WARN("No DevKey for 0x%04x", ctx->addr);
return -EINVAL;
}
node = bt_mesh_cdb_node_get(ctx->addr);
if (!node) {
BT_WARN("No DevKey for 0x%04x", ctx->addr);
return -EINVAL;
}
*app_key = node->dev_key;
} else {
*app_key = bt_mesh.dev_key;
}
*aid = 0;
return 0;
}
app = app_get(ctx->app_idx);
if (!app) {
BT_WARN("Unknown AppKey 0x%03x", ctx->app_idx);
return -EINVAL;
}
*sub = bt_mesh_subnet_get(app->net_idx);
if (!*sub) {
BT_WARN("Unknown NetKey 0x%03x", app->net_idx);
return -EINVAL;
}
if ((*sub)->kr_phase == BT_MESH_KR_PHASE_2 && app->updated) {
*aid = app->keys[1].id;
*app_key = app->keys[1].val;
} else {
*aid = app->keys[0].id;
*app_key = app->keys[0].val;
}
return 0;
}
uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid,
struct bt_mesh_net_rx *rx,
int (*cb)(struct bt_mesh_net_rx *rx,
const uint8_t key[16], void *cb_data),
void *cb_data)
{
int err, i;
if (dev_key) {
/* Attempt remote dev key first, as that is only available for
* provisioner devices, which normally don't interact with nodes
* that know their local dev key.
*/
if (IS_ENABLED(CONFIG_BT_MESH_CDB) &&
rx->net_if != BT_MESH_NET_IF_LOCAL) {
struct bt_mesh_cdb_node *node;
node = bt_mesh_cdb_node_get(rx->ctx.addr);
if (node && !cb(rx, node->dev_key, cb_data)) {
return BT_MESH_KEY_DEV_REMOTE;
}
}
/** Bluetooth Mesh Specification v1.0.1, section 3.4.3:
* The Device key is only valid for unicast addresses.
*/
if (BT_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) {
err = cb(rx, bt_mesh.dev_key, cb_data);
if (!err) {
return BT_MESH_KEY_DEV_LOCAL;
}
}
return BT_MESH_KEY_UNUSED;
}
for (i = 0; i < ARRAY_SIZE(apps); i++) {
const struct bt_mesh_app_key *app = &apps[i];
const struct bt_mesh_app_cred *cred;
if (app->app_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (app->net_idx != rx->sub->net_idx) {
continue;
}
if (rx->new_key && app->updated) {
cred = &app->keys[1];
} else {
cred = &app->keys[0];
}
if (cred->id != aid) {
continue;
}
err = cb(rx, cred->val, cb_data);
if (err) {
continue;
}
return app->app_idx;
}
return BT_MESH_KEY_UNUSED;
}
void bt_mesh_app_keys_reset(void)
{
for (int i = 0; i < ARRAY_SIZE(apps); i++) {
struct bt_mesh_app_key *app = &apps[i];
if (app->app_idx != BT_MESH_KEY_UNUSED) {
app_key_del(app);
}
}
}
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BT_MESH_APP_KEYS_H_
#define _BT_MESH_APP_KEYS_H_
#include "../include/mesh/mesh.h"
#include "subnet.h"
/** Mesh Application. */
struct bt_mesh_app_key {
uint16_t net_idx;
uint16_t app_idx;
bool updated;
struct bt_mesh_app_cred {
uint8_t id;
uint8_t val[16];
} keys[2];
};
/** @brief Reset the app keys module. */
void bt_mesh_app_keys_reset(void);
/** @brief Get the application key with the given AppIdx.
*
* @param app_idx App index.
*
* @return The matching application, or NULL if the application isn't known.
*/
struct bt_mesh_app_key *bt_mesh_app_key_get(uint16_t app_idx);
/** @brief Initialize a new application key with the given parameters.
*
* @param app_idx AppIndex.
* @param net_idx NetIndex the application is bound to.
* @param old_key Current application key.
* @param new_key Updated application key, or NULL if not known.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_app_key_set(uint16_t app_idx, uint16_t net_idx,
const uint8_t old_key[16], const uint8_t new_key[16]);
/** @brief Resolve the message encryption keys, given a message context.
*
* Will use the @c ctx::app_idx and @c ctx::net_idx fields to find a pair of
* message encryption keys. If @c ctx::app_idx represents a device key, the
* @c ctx::net_idx will be used to determine the net key. Otherwise, the
* @c ctx::net_idx parameter will be ignored.
*
* @param ctx Message context.
* @param sub Subnet return parameter.
* @param app_key Application return parameter.
* @param aid Application ID return parameter.
*
* @return 0 on success, or (negative) error code on failure.
*/
int bt_mesh_keys_resolve(struct bt_mesh_msg_ctx *ctx,
struct bt_mesh_subnet **sub,
const uint8_t **app_key, uint8_t *aid);
/** @brief Iterate through all matching application keys and call @c cb on each.
*
* @param dev_key Whether to return device keys.
* @param aid 7 bit application ID to match.
* @param rx RX structure to match against.
* @param cb Callback to call for every valid app key.
* @param cb_data Callback data to pass to the callback.
*
* @return The AppIdx that yielded a 0-return from the callback.
*/
uint16_t bt_mesh_app_key_find(bool dev_key, uint8_t aid,
struct bt_mesh_net_rx *rx,
int (*cb)(struct bt_mesh_net_rx *rx,
const uint8_t key[16], void *cb_data),
void *cb_data);
struct bt_mesh_app_key *app_get(uint16_t app_idx);
extern void (*bt_mesh_app_key_cb_list[1]) (uint16_t app_idx, uint16_t net_idx,
enum bt_mesh_key_evt evt);
#endif /* _BT_MESH_APP_KEYS_H_ */

View File

@@ -23,8 +23,8 @@
#include "crypto.h"
#include "beacon.h"
#include "foundation.h"
#include "atomic.h"
#define UNPROVISIONED_INTERVAL (K_SECONDS(5))
#define PROVISIONED_INTERVAL (K_SECONDS(10))
#define BEACON_TYPE_UNPROVISIONED 0x00
@@ -38,26 +38,12 @@
static struct k_delayed_work beacon_timer;
static struct bt_mesh_subnet *cache_check(u8_t data[21])
static int cache_check(struct bt_mesh_subnet *sub, void *beacon_data)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (!memcmp(sub->beacon_cache, data, 21)) {
return sub;
}
}
return NULL;
return !memcmp(sub->beacon_cache, beacon_data, 21);
}
static void cache_add(u8_t data[21], struct bt_mesh_subnet *sub)
static void cache_add(uint8_t data[21], struct bt_mesh_subnet *sub)
{
memcpy(sub->beacon_cache, data, 21);
}
@@ -74,16 +60,12 @@ static void beacon_complete(int err, void *user_data)
void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
struct os_mbuf *buf)
{
u8_t flags = bt_mesh_net_flags(sub);
uint8_t flags = bt_mesh_net_flags(sub);
struct bt_mesh_subnet_keys *keys;
net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE);
if (sub->kr_flag) {
keys = &sub->keys[1];
} else {
keys = &sub->keys[0];
}
keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)];
net_buf_simple_add_u8(buf, flags);
@@ -105,53 +87,43 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
#define BEACON_THRESHOLD(sub) (K_SECONDS(10 * ((sub)->beacons_last + 1)) - \
K_SECONDS(5))
static int secure_beacon_send(void)
static int secure_beacon_send(struct bt_mesh_subnet *sub, void *cb_data)
{
static const struct bt_mesh_send_cb send_cb = {
.end = beacon_complete,
};
u32_t now = k_uptime_get_32();
int i;
uint32_t now = k_uptime_get_32();
struct os_mbuf *buf;
uint32_t time_diff;
BT_DBG("");
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
struct os_mbuf *buf;
u32_t time_diff;
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
time_diff = now - sub->beacon_sent;
if (time_diff < K_SECONDS(600) &&
time_diff < BEACON_THRESHOLD(sub)) {
continue;
}
buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, PROV_XMIT,
K_NO_WAIT);
if (!buf) {
BT_ERR("Unable to allocate beacon buffer");
return -ENOBUFS;
}
bt_mesh_beacon_create(sub, buf);
bt_mesh_adv_send(buf, &send_cb, sub);
net_buf_unref(buf);
time_diff = now - sub->beacon_sent;
if (time_diff < (600 * MSEC_PER_SEC) &&
time_diff < BEACON_THRESHOLD(sub)) {
return 0;
}
buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, PROV_XMIT, K_NO_WAIT);
if (!buf) {
BT_ERR("Unable to allocate beacon buffer");
return -ENOMEM;
}
bt_mesh_beacon_create(sub, buf);
bt_mesh_adv_send(buf, &send_cb, sub);
net_buf_unref(buf);
return 0;
}
static int unprovisioned_beacon_send(void)
{
const struct bt_mesh_prov *prov;
u8_t uri_hash[16] = { 0 };
uint8_t uri_hash[16] = { 0 };
struct os_mbuf *buf;
u16_t oob_info;
uint16_t oob_info;
BT_DBG("unprovisioned_beacon_send");
@@ -204,12 +176,11 @@ static int unprovisioned_beacon_send(void)
static void unprovisioned_beacon_recv(struct os_mbuf *buf)
{
#if MYNEWT_VAL(BLE_MESH_PB_ADV)
const struct bt_mesh_prov *prov;
u8_t *uuid;
u16_t oob_info;
u32_t uri_hash_val;
u32_t *uri_hash = NULL;
uint8_t *uuid;
uint16_t oob_info;
uint32_t uri_hash_val;
uint32_t *uri_hash = NULL;
if (buf->om_len != 18 && buf->om_len != 22) {
BT_ERR("Invalid unprovisioned beacon length (%u)", buf->om_len);
@@ -233,13 +204,17 @@ static void unprovisioned_beacon_recv(struct os_mbuf *buf)
(bt_mesh_prov_oob_info_t)oob_info,
uri_hash);
}
#endif
}
static void sub_update_beacon_observation(struct bt_mesh_subnet *sub)
{
sub->beacons_last = sub->beacons_cur;
sub->beacons_cur = 0U;
}
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
@@ -250,23 +225,15 @@ static void update_beacon_observation(void)
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;
}
bt_mesh_subnet_foreach(sub_update_beacon_observation);
}
static void beacon_send(struct ble_npl_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);
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && bt_mesh_prov_active()) {
k_delayed_work_submit(&beacon_timer,
K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT)));
return;
}
@@ -274,34 +241,81 @@ static void beacon_send(struct ble_npl_event *work)
if (bt_mesh_is_provisioned()) {
update_beacon_observation();
secure_beacon_send();
(void)bt_mesh_subnet_find(secure_beacon_send, NULL);
/* Only resubmit if beaconing is still enabled */
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED ||
if (bt_mesh_beacon_enabled() ||
atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR)) {
k_delayed_work_submit(&beacon_timer,
PROVISIONED_INTERVAL);
}
} else if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
unprovisioned_beacon_send();
k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL);
return;
}
if (IS_ENABLED(BLE_MESH_PB_ADV)) {
unprovisioned_beacon_send();
k_delayed_work_submit(&beacon_timer,
K_SECONDS(MYNEWT_VAL(BLE_MESH_UNPROV_BEACON_INT)));
}
}
struct beacon_params {
const uint8_t *net_id;
const uint8_t *auth;
uint32_t iv_index;
uint8_t flags;
bool new_key;
};
static bool auth_match(struct bt_mesh_subnet_keys *keys,
const struct beacon_params *params)
{
uint8_t net_auth[8];
if (memcmp(params->net_id, keys->net_id, 8)) {
return false;
}
bt_mesh_beacon_auth(keys->beacon, params->flags, keys->net_id,
params->iv_index, net_auth);
if (memcmp(params->auth, net_auth, 8)) {
BT_WARN("Authentication Value %s != %s",
bt_hex(params->auth, 8), bt_hex(net_auth, 8));
return false;
}
return true;
}
static int subnet_by_id(struct bt_mesh_subnet *sub, void *cb_data)
{
struct beacon_params *params = cb_data;
for (int i = 0; i < ARRAY_SIZE(sub->keys); i++) {
if (sub->keys[i].valid && auth_match(&sub->keys[i], params)) {
params->new_key = (i > 0);
return true;
}
}
return false;
}
static void secure_beacon_recv(struct os_mbuf *buf)
{
u8_t *data, *net_id, *auth;
struct beacon_params params;
struct bt_mesh_subnet *sub;
u32_t iv_index;
bool new_key, kr_change, iv_change;
u8_t flags;
uint8_t *data;
if (buf->om_len < 21) {
BT_ERR("Too short secure beacon (len %u)", buf->om_len);
return;
}
sub = cache_check(buf->om_data);
sub = bt_mesh_subnet_find(cache_check, buf->om_data);
if (sub) {
/* We've seen this beacon before - just update the stats */
goto update_stats;
@@ -310,27 +324,30 @@ static void secure_beacon_recv(struct os_mbuf *buf)
/* So we can add to the cache if auth matches */
data = buf->om_data;
flags = net_buf_simple_pull_u8(buf);
net_id = net_buf_simple_pull_mem(buf, 8);
iv_index = net_buf_simple_pull_be32(buf);
auth = buf->om_data;
params.flags = net_buf_simple_pull_u8(buf);
params.net_id = net_buf_simple_pull_mem(buf, 8);
params.iv_index = net_buf_simple_pull_be32(buf);
params.auth = buf->om_data;
BT_DBG("flags 0x%02x id %s iv_index 0x%08x",
flags, bt_hex(net_id, 8), (unsigned) iv_index);
params.flags, bt_hex(params.net_id, 8), params.iv_index);
sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key);
sub = bt_mesh_subnet_find(subnet_by_id, &params);
if (!sub) {
BT_DBG("No subnet that matched beacon");
return;
}
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !new_key) {
if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !params.new_key) {
BT_WARN("Ignoring Phase 2 KR Update secured using old key");
return;
}
cache_add(data, sub);
bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(params.flags),
params.new_key);
/* 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) {
@@ -339,31 +356,18 @@ static void secure_beacon_recv(struct os_mbuf *buf)
}
BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x",
sub->net_idx, (unsigned) iv_index, (unsigned) bt_mesh.iv_index);
sub->net_idx, params.iv_index, bt_mesh.iv_index);
if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) &&
(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ==
BT_MESH_IV_UPDATE(flags))) {
BT_MESH_IV_UPDATE(params.flags))) {
bt_mesh_beacon_ivu_initiator(false);
}
iv_change = bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(flags));
kr_change = bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(flags), new_key);
if (kr_change) {
bt_mesh_net_beacon_update(sub);
}
if (iv_change) {
/* Update all subnets */
bt_mesh_net_sec_update(NULL);
} else if (kr_change) {
/* Key Refresh without IV Update only impacts one subnet */
bt_mesh_net_sec_update(sub);
}
bt_mesh_net_iv_update(params.iv_index, BT_MESH_IV_UPDATE(params.flags));
update_stats:
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED &&
if (bt_mesh_beacon_enabled() &&
sub->beacons_cur < 0xff) {
sub->beacons_cur++;
}
@@ -371,7 +375,7 @@ update_stats:
void bt_mesh_beacon_recv(struct os_mbuf *buf)
{
u8_t type;
uint8_t type;
BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
@@ -383,7 +387,9 @@ void bt_mesh_beacon_recv(struct os_mbuf *buf)
type = net_buf_simple_pull_u8(buf);
switch (type) {
case BEACON_TYPE_UNPROVISIONED:
unprovisioned_beacon_recv(buf);
if (IS_ENABLED(BLE_MESH_PB_ADV)) {
unprovisioned_beacon_recv(buf);
}
break;
case BEACON_TYPE_SECURE:
secure_beacon_recv(buf);
@@ -394,8 +400,38 @@ void bt_mesh_beacon_recv(struct os_mbuf *buf)
}
}
void bt_mesh_beacon_update(struct bt_mesh_subnet *sub)
{
uint8_t flags = bt_mesh_net_flags(sub);
struct bt_mesh_subnet_keys *keys;
int err;
keys = &sub->keys[SUBNET_KEY_TX_IDX(sub)];
BT_DBG("NetIndex 0x%03x Using %s key", sub->net_idx,
SUBNET_KEY_TX_IDX(sub) ? "new" : "current");
BT_DBG("flags 0x%02x, IVI 0x%08x", flags, bt_mesh.iv_index);
err = bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id,
bt_mesh.iv_index, sub->auth);
if (err) {
BT_ERR("Failed updating net beacon for 0x%03x", sub->net_idx);
}
}
static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
{
if (evt != BT_MESH_KEY_DELETED) {
bt_mesh_beacon_update(sub);
}
}
void bt_mesh_beacon_init(void)
{
if (!bt_mesh_subnet_cb_list[1]) {
bt_mesh_subnet_cb_list[1] = subnet_evt;
}
k_delayed_work_init(&beacon_timer, beacon_send);
}
@@ -404,35 +440,30 @@ void bt_mesh_beacon_ivu_initiator(bool enable)
atomic_set_bit_to(bt_mesh.flags, 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_submit(&beacon_timer, K_NO_WAIT);
} else if (!bt_mesh_beacon_enabled()) {
k_delayed_work_cancel(&beacon_timer);
}
}
static void subnet_beacon_enable(struct bt_mesh_subnet *sub)
{
sub->beacons_last = 0U;
sub->beacons_cur = 0U;
bt_mesh_beacon_update(sub);
}
void bt_mesh_beacon_enable(void)
{
int i;
if (!bt_mesh_is_provisioned()) {
k_work_submit(&beacon_timer.work);
k_delayed_work_submit(&beacon_timer, K_NO_WAIT);
return;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
bt_mesh_subnet_foreach(subnet_beacon_enable);
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);
k_delayed_work_submit(&beacon_timer, K_NO_WAIT);
}
void bt_mesh_beacon_disable(void)

View File

@@ -22,5 +22,6 @@ void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
struct os_mbuf *buf);
void bt_mesh_beacon_init(void);
void bt_mesh_beacon_update(struct bt_mesh_subnet *sub);
#endif

View File

@@ -0,0 +1,393 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_CDB)
#define LOG_MODULE_NAME bt_mesh_cdb
#include "nimble/porting/nimble/include/log/log.h"
#include "../include/mesh/mesh.h"
#include "net.h"
#include "rpl.h"
#include "settings.h"
#include "mesh_priv.h"
#include "../include/mesh/glue.h"
#if MYNEWT_VAL(BLE_MESH_CDB)
struct bt_mesh_cdb bt_mesh_cdb = {
.nodes = {
[0 ... (CONFIG_BT_MESH_NODE_COUNT - 1)] = {
.addr = BT_MESH_ADDR_UNASSIGNED,
}
},
.subnets = {
[0 ... (CONFIG_BT_MESH_SUBNET_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
.app_keys = {
[0 ... (CONFIG_BT_MESH_APP_KEY_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
};
/*
* Check if an address range from addr_start for addr_start + num_elem - 1 is
* free for use. When a conflict is found, next will be set to the next address
* available after the conflicting range and -EAGAIN will be returned.
*/
static int addr_is_free(uint16_t addr_start, uint8_t num_elem, uint16_t *next)
{
uint16_t addr_end = addr_start + num_elem - 1;
uint16_t other_start, other_end;
int i;
if (!BT_MESH_ADDR_IS_UNICAST(addr_start) ||
!BT_MESH_ADDR_IS_UNICAST(addr_end) ||
num_elem == 0) {
return -EINVAL;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
continue;
}
other_start = node->addr;
other_end = other_start + node->num_elem - 1;
if (!(addr_end < other_start || addr_start > other_end)) {
if (next) {
*next = other_end + 1;
}
return -EAGAIN;
}
}
return 0;
}
/*
* Find the lowest possible starting address that can fit num_elem elements. If
* a free address range cannot be found, BT_MESH_ADDR_UNASSIGNED will be
* returned. Otherwise the first address in the range is returned.
*
* NOTE: This is quite an ineffective algorithm as it might need to look
* through the array of nodes N+2 times. A more effective algorithm
* could be used if the nodes were stored in a sorted list.
*/
static uint16_t find_lowest_free_addr(uint8_t num_elem)
{
uint16_t addr = 1, next = 0;
int err, i;
/*
* It takes a maximum of node count + 2 to find a free address if there
* is any. +1 for our own address and +1 for making sure that the
* address range is valid.
*/
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes) + 2; ++i) {
err = addr_is_free(addr, num_elem, &next);
if (err == 0) {
break;
} else if (err != -EAGAIN) {
addr = BT_MESH_ADDR_UNASSIGNED;
break;
}
addr = next;
}
return addr;
}
int bt_mesh_cdb_create(const uint8_t key[16])
{
struct bt_mesh_cdb_subnet *sub;
if (atomic_test_and_set_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_VALID)) {
return -EALREADY;
}
sub = bt_mesh_cdb_subnet_alloc(BT_MESH_KEY_PRIMARY);
if (sub == NULL) {
return -ENOMEM;
}
memcpy(sub->keys[0].net_key, key, 16);
bt_mesh_cdb.iv_index = 0;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb();
bt_mesh_store_cdb_subnet(sub);
}
return 0;
}
void bt_mesh_cdb_clear(void)
{
int i;
atomic_clear_bit(bt_mesh_cdb.flags, BT_MESH_CDB_VALID);
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) {
if (bt_mesh_cdb.nodes[i].addr != BT_MESH_ADDR_UNASSIGNED) {
bt_mesh_cdb_node_del(&bt_mesh_cdb.nodes[i], true);
}
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
if (bt_mesh_cdb.subnets[i].net_idx != BT_MESH_KEY_UNUSED) {
bt_mesh_cdb_subnet_del(&bt_mesh_cdb.subnets[i], true);
}
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) {
if (bt_mesh_cdb.app_keys[i].net_idx != BT_MESH_KEY_UNUSED) {
bt_mesh_cdb_app_key_del(&bt_mesh_cdb.app_keys[i], true);
}
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb();
}
}
void bt_mesh_cdb_iv_update(uint32_t iv_index, bool iv_update)
{
BT_DBG("Updating IV index to %d\n", iv_index);
bt_mesh_cdb.iv_index = iv_index;
atomic_set_bit_to(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS,
iv_update);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb();
}
}
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_alloc(uint16_t net_idx)
{
struct bt_mesh_cdb_subnet *sub;
int i;
if (bt_mesh_cdb_subnet_get(net_idx) != NULL) {
return NULL;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
sub = &bt_mesh_cdb.subnets[i];
if (sub->net_idx != BT_MESH_KEY_UNUSED) {
continue;
}
sub->net_idx = net_idx;
return sub;
}
return NULL;
}
void bt_mesh_cdb_subnet_del(struct bt_mesh_cdb_subnet *sub, bool store)
{
BT_DBG("NetIdx 0x%03x store %u", sub->net_idx, store);
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
bt_mesh_clear_cdb_subnet(sub);
}
sub->net_idx = BT_MESH_KEY_UNUSED;
memset(sub->keys, 0, sizeof(sub->keys));
}
struct bt_mesh_cdb_subnet *bt_mesh_cdb_subnet_get(uint16_t net_idx)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.subnets); ++i) {
if (bt_mesh_cdb.subnets[i].net_idx == net_idx) {
return &bt_mesh_cdb.subnets[i];
}
}
return NULL;
}
void bt_mesh_cdb_subnet_store(const struct bt_mesh_cdb_subnet *sub)
{
if (MYNEWT_VAL(BLE_MESH_SETTINGS)) {
bt_mesh_store_cdb_subnet(sub);
}
}
uint8_t bt_mesh_cdb_subnet_flags(const struct bt_mesh_cdb_subnet *sub)
{
uint8_t flags = 0x00;
if (sub && sub->kr_flag) {
flags |= BT_MESH_NET_FLAG_KR;
}
if (atomic_test_bit(bt_mesh_cdb.flags, BT_MESH_CDB_IVU_IN_PROGRESS)) {
flags |= BT_MESH_NET_FLAG_IVU;
}
return flags;
}
struct bt_mesh_cdb_node *bt_mesh_cdb_node_alloc(const uint8_t uuid[16], uint16_t addr,
uint8_t num_elem, uint16_t net_idx)
{
int i;
if (addr == BT_MESH_ADDR_UNASSIGNED) {
addr = find_lowest_free_addr(num_elem);
if (addr == BT_MESH_ADDR_UNASSIGNED) {
return NULL;
}
} else if (addr_is_free(addr, num_elem, NULL) < 0) {
BT_DBG("Address range 0x%04x-0x%04x is not free", addr,
addr + num_elem - 1);
return NULL;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
memcpy(node->uuid, uuid, 16);
node->addr = addr;
node->num_elem = num_elem;
node->net_idx = net_idx;
atomic_set(node->flags, 0);
return node;
}
}
return NULL;
}
void bt_mesh_cdb_node_del(struct bt_mesh_cdb_node *node, bool store)
{
BT_DBG("Node addr 0x%04x store %u", node->addr, store);
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
bt_mesh_clear_cdb_node(node);
}
node->addr = BT_MESH_ADDR_UNASSIGNED;
memset(node->dev_key, 0, sizeof(node->dev_key));
}
struct bt_mesh_cdb_node *bt_mesh_cdb_node_get(uint16_t addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); i++) {
struct bt_mesh_cdb_node *node = &bt_mesh_cdb.nodes[i];
if (addr >= node->addr &&
addr <= node->addr + node->num_elem - 1) {
return node;
}
}
return NULL;
}
void bt_mesh_cdb_node_store(const struct bt_mesh_cdb_node *node)
{
if (MYNEWT_VAL(BLE_MESH_SETTINGS)) {
bt_mesh_store_cdb_node(node);
}
}
void bt_mesh_cdb_node_foreach(bt_mesh_cdb_node_func_t func, void *user_data)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.nodes); ++i) {
if (bt_mesh_cdb.nodes[i].addr == BT_MESH_ADDR_UNASSIGNED) {
continue;
}
if (func(&bt_mesh_cdb.nodes[i], user_data) ==
BT_MESH_CDB_ITER_STOP) {
break;
}
}
}
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_alloc(uint16_t net_idx,
uint16_t app_idx)
{
struct bt_mesh_cdb_app_key *key;
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); ++i) {
key = &bt_mesh_cdb.app_keys[i];
if (key->net_idx != BT_MESH_KEY_UNUSED) {
continue;
}
key->net_idx = net_idx;
key->app_idx = app_idx;
return key;
}
return NULL;
}
void bt_mesh_cdb_app_key_del(struct bt_mesh_cdb_app_key *key, bool store)
{
BT_DBG("AppIdx 0x%03x store %u", key->app_idx, store);
if (IS_ENABLED(CONFIG_BT_SETTINGS) && store) {
bt_mesh_clear_cdb_app_key(key);
}
key->net_idx = BT_MESH_ADDR_UNASSIGNED;
memset(key->keys, 0, sizeof(key->keys));
}
struct bt_mesh_cdb_app_key *bt_mesh_cdb_app_key_get(uint16_t app_idx)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh_cdb.app_keys); i++) {
struct bt_mesh_cdb_app_key *key = &bt_mesh_cdb.app_keys[i];
if (key->net_idx != BT_MESH_KEY_UNUSED &&
key->app_idx == app_idx) {
return key;
}
}
return NULL;
}
void bt_mesh_cdb_app_key_store(const struct bt_mesh_cdb_app_key *key)
{
if (MYNEWT_VAL(BLE_MESH_SETTINGS)) {
bt_mesh_store_cdb_app_key(key);
}
}
#endif
#endif // MYNEWT_VAL(BLE_MESH)

View File

@@ -0,0 +1,272 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#include "../include/mesh/mesh.h"
#include "mesh_priv.h"
#include "net.h"
#include "rpl.h"
#include "beacon.h"
#include "settings.h"
#include "heartbeat.h"
#include "friend.h"
#include "cfg.h"
#include "../include/mesh/glue.h"
void bt_mesh_beacon_set(bool beacon)
{
if (atomic_test_bit(bt_mesh.flags, BT_MESH_BEACON) == beacon) {
return;
}
atomic_set_bit_to(bt_mesh.flags, BT_MESH_BEACON, beacon);
if (beacon) {
bt_mesh_beacon_enable();
} else {
bt_mesh_beacon_disable();
}
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
bt_mesh_store_cfg();
}
}
bool bt_mesh_beacon_enabled(void)
{
return atomic_test_bit(bt_mesh.flags, BT_MESH_BEACON);
}
static int feature_set(int feature_flag, enum bt_mesh_feat_state state)
{
if (state != BT_MESH_FEATURE_DISABLED &&
state != BT_MESH_FEATURE_ENABLED) {
return -EINVAL;
}
if (atomic_test_bit(bt_mesh.flags, feature_flag) ==
(state == BT_MESH_FEATURE_ENABLED)) {
return -EALREADY;
}
atomic_set_bit_to(bt_mesh.flags, feature_flag,
(state == BT_MESH_FEATURE_ENABLED));
return 0;
}
static enum bt_mesh_feat_state feature_get(int feature_flag)
{
return atomic_test_bit(bt_mesh.flags, feature_flag) ?
BT_MESH_FEATURE_ENABLED :
BT_MESH_FEATURE_DISABLED;
}
int bt_mesh_gatt_proxy_set(enum bt_mesh_feat_state gatt_proxy)
{
int err;
if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
return -ENOTSUP;
}
err = feature_set(BT_MESH_GATT_PROXY, gatt_proxy);
if (err) {
return err;
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_PROXY);
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
bt_mesh_store_cfg();
}
return 0;
}
enum bt_mesh_feat_state bt_mesh_gatt_proxy_get(void)
{
if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
return BT_MESH_FEATURE_NOT_SUPPORTED;
}
return feature_get(BT_MESH_GATT_PROXY);
}
int bt_mesh_default_ttl_set(uint8_t default_ttl)
{
if (default_ttl == 1 || default_ttl > BT_MESH_TTL_MAX) {
return -EINVAL;
}
if (default_ttl == bt_mesh.default_ttl) {
return 0;
}
bt_mesh.default_ttl = default_ttl;
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
bt_mesh_store_cfg();
}
return 0;
}
uint8_t bt_mesh_default_ttl_get(void)
{
return bt_mesh.default_ttl;
}
int bt_mesh_friend_set(enum bt_mesh_feat_state friendship)
{
int err;
if (!IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
return -ENOTSUP;
}
err = feature_set(BT_MESH_FRIEND, friendship);
if (err) {
return err;
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_FRIEND);
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
bt_mesh_store_cfg();
}
if (friendship == BT_MESH_FEATURE_DISABLED) {
bt_mesh_friends_clear();
}
return 0;
}
enum bt_mesh_feat_state bt_mesh_friend_get(void)
{
if (!IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
return BT_MESH_FEATURE_NOT_SUPPORTED;
}
return feature_get(BT_MESH_FRIEND);
}
void bt_mesh_net_transmit_set(uint8_t xmit)
{
if (bt_mesh.net_xmit == xmit) {
return;
}
bt_mesh.net_xmit = xmit;
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
bt_mesh_store_cfg();
}
}
uint8_t bt_mesh_net_transmit_get(void)
{
return bt_mesh.net_xmit;
}
int bt_mesh_relay_set(enum bt_mesh_feat_state relay, uint8_t xmit)
{
int err;
if (!CONFIG_BT_MESH_RELAY) {
return -ENOTSUP;
}
err = feature_set(BT_MESH_RELAY, relay);
if (err == -EINVAL) {
return err;
}
if (err == -EALREADY && bt_mesh.relay_xmit == xmit) {
return -EALREADY;
}
bt_mesh.relay_xmit = xmit;
bt_mesh_hb_feature_changed(BT_MESH_FEAT_RELAY);
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
bt_mesh_store_cfg();
}
return 0;
}
enum bt_mesh_feat_state bt_mesh_relay_get(void)
{
return feature_get(BT_MESH_RELAY);
}
uint8_t bt_mesh_relay_retransmit_get(void)
{
if (!CONFIG_BT_MESH_RELAY) {
return 0;
}
return bt_mesh.relay_xmit;
}
bool bt_mesh_fixed_group_match(uint16_t addr)
{
/* Check for fixed group addresses */
switch (addr) {
case BT_MESH_ADDR_ALL_NODES:
return true;
case BT_MESH_ADDR_PROXIES:
return (bt_mesh_gatt_proxy_get() == BT_MESH_FEATURE_ENABLED);
case BT_MESH_ADDR_FRIENDS:
return (bt_mesh_friend_get() == BT_MESH_FEATURE_ENABLED);
case BT_MESH_ADDR_RELAYS:
return (bt_mesh_relay_get() == BT_MESH_FEATURE_ENABLED);
default:
return false;
}
}
void bt_mesh_cfg_init(void)
{
bt_mesh.default_ttl = CONFIG_BT_MESH_DEFAULT_TTL;
bt_mesh.net_xmit =
BT_MESH_TRANSMIT(CONFIG_BT_MESH_NETWORK_TRANSMIT_COUNT,
CONFIG_BT_MESH_NETWORK_TRANSMIT_INTERVAL);
#if defined(CONFIG_BT_MESH_RELAY)
bt_mesh.relay_xmit =
BT_MESH_TRANSMIT(CONFIG_BT_MESH_RELAY_RETRANSMIT_COUNT,
CONFIG_BT_MESH_RELAY_RETRANSMIT_INTERVAL);
#endif
if (CONFIG_BT_MESH_RELAY_ENABLED) {
atomic_set_bit(bt_mesh.flags, BT_MESH_RELAY);
}
if (CONFIG_BT_MESH_BEACON_ENABLED) {
atomic_set_bit(bt_mesh.flags, BT_MESH_BEACON);
}
if (CONFIG_BT_MESH_GATT_PROXY_ENABLED) {
atomic_set_bit(bt_mesh.flags, BT_MESH_GATT_PROXY);
}
if (CONFIG_BT_MESH_FRIEND_ENABLED) {
atomic_set_bit(bt_mesh.flags, BT_MESH_FRIEND);
}
}
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,9 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
void bt_mesh_cfg_init(void);
bool bt_mesh_fixed_group_match(uint16_t addr);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -38,8 +38,8 @@
#define APP_MIC_LEN(aszmic) ((aszmic) ? 8 : 4)
#if MYNEWT_VAL(BLE_CRYPTO_STACK_MBEDTLS)
int bt_mesh_aes_cmac(const u8_t key[16], struct bt_mesh_sg *sg,
size_t sg_len, u8_t mac[16])
int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg,
size_t sg_len, uint8_t mac[16])
{
int rc = BLE_HS_EUNKNOWN;
mbedtls_cipher_context_t ctx = {0};
@@ -80,8 +80,8 @@ exit:
}
#else
int bt_mesh_aes_cmac(const u8_t key[16], struct bt_mesh_sg *sg,
size_t sg_len, u8_t mac[16])
int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg,
size_t sg_len, uint8_t mac[16])
{
struct tc_aes_key_sched_struct sched;
struct tc_cmac_struct state;
@@ -105,8 +105,8 @@ int bt_mesh_aes_cmac(const u8_t key[16], struct bt_mesh_sg *sg,
}
#endif
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 bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16],
const char *info, uint8_t okm[16])
{
int err;
@@ -118,14 +118,14 @@ int bt_mesh_k1(const u8_t *ikm, size_t ikm_len, const u8_t salt[16],
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])
int bt_mesh_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
uint8_t net_id[1], uint8_t enc_key[16], uint8_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;
uint8_t salt[16];
uint8_t out[16];
uint8_t t[16];
uint8_t pad;
int err;
BT_DBG("n %s", bt_hex(n, 16));
@@ -183,11 +183,11 @@ int bt_mesh_k2(const u8_t n[16], const u8_t *p, size_t p_len,
return 0;
}
int bt_mesh_k3(const u8_t n[16], u8_t out[8])
int bt_mesh_k3(const uint8_t n[16], uint8_t out[8])
{
u8_t id64[] = { 'i', 'd', '6', '4', 0x01 };
u8_t tmp[16];
u8_t t[16];
uint8_t id64[] = { 'i', 'd', '6', '4', 0x01 };
uint8_t tmp[16];
uint8_t t[16];
int err;
err = bt_mesh_s1("smk3", tmp);
@@ -210,11 +210,11 @@ int bt_mesh_k3(const u8_t n[16], u8_t out[8])
return 0;
}
int bt_mesh_k4(const u8_t n[16], u8_t out[1])
int bt_mesh_k4(const uint8_t n[16], uint8_t out[1])
{
u8_t id6[] = { 'i', 'd', '6', 0x01 };
u8_t tmp[16];
u8_t t[16];
uint8_t id6[] = { 'i', 'd', '6', 0x01 };
uint8_t tmp[16];
uint8_t t[16];
int err;
err = bt_mesh_s1("smk4", tmp);
@@ -237,10 +237,10 @@ int bt_mesh_k4(const u8_t n[16], u8_t out[1])
return 0;
}
int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16])
int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16])
{
const char *id128 = "id128\x01";
u8_t salt[16];
uint8_t salt[16];
int err;
err = bt_mesh_s1(s, salt);
@@ -251,326 +251,8 @@ int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16])
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 < 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 < 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;
}
static void create_proxy_nonce(u8_t nonce[13], const u8_t *pdu,
u32_t iv_index)
static void create_proxy_nonce(uint8_t nonce[13], const uint8_t *pdu,
uint32_t iv_index)
{
/* Nonce Type */
nonce[0] = 0x03;
@@ -595,8 +277,8 @@ static void create_proxy_nonce(u8_t nonce[13], const u8_t *pdu,
sys_put_be32(iv_index, &nonce[9]);
}
static void create_net_nonce(u8_t nonce[13], const u8_t *pdu,
u32_t iv_index)
static void create_net_nonce(uint8_t nonce[13], const uint8_t *pdu,
uint32_t iv_index)
{
/* Nonce Type */
nonce[0] = 0x00;
@@ -621,11 +303,11 @@ static void create_net_nonce(u8_t nonce[13], const u8_t *pdu,
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])
int bt_mesh_net_obfuscate(uint8_t *pdu, uint32_t iv_index,
const uint8_t privacy_key[16])
{
u8_t priv_rand[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
u8_t tmp[16];
uint8_t priv_rand[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, };
uint8_t tmp[16];
int err, i;
BT_DBG("IVIndex %u, PrivacyKey %s", (unsigned) iv_index,
@@ -648,11 +330,11 @@ int bt_mesh_net_obfuscate(u8_t *pdu, u32_t iv_index,
return 0;
}
int bt_mesh_net_encrypt(const u8_t key[16], struct os_mbuf *buf,
u32_t iv_index, bool proxy)
int bt_mesh_net_encrypt(const uint8_t key[16], struct os_mbuf *buf,
uint32_t iv_index, bool proxy)
{
u8_t mic_len = NET_MIC_LEN(buf->om_data);
u8_t nonce[13];
uint8_t mic_len = NET_MIC_LEN(buf->om_data);
uint8_t nonce[13];
int err;
BT_DBG("IVIndex %u EncKey %s mic_len %u", (unsigned) iv_index,
@@ -667,7 +349,7 @@ int bt_mesh_net_encrypt(const u8_t key[16], struct os_mbuf *buf,
BT_DBG("Nonce %s", bt_hex(nonce, 13));
err = bt_mesh_ccm_encrypt(key, nonce, &buf->om_data[7], buf->om_len - 7,
err = bt_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);
@@ -676,11 +358,11 @@ int bt_mesh_net_encrypt(const u8_t key[16], struct os_mbuf *buf,
return err;
}
int bt_mesh_net_decrypt(const u8_t key[16], struct os_mbuf *buf,
u32_t iv_index, bool proxy)
int bt_mesh_net_decrypt(const uint8_t key[16], struct os_mbuf *buf,
uint32_t iv_index, bool proxy)
{
u8_t mic_len = NET_MIC_LEN(buf->om_data);
u8_t nonce[13];
uint8_t mic_len = NET_MIC_LEN(buf->om_data);
uint8_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", (unsigned) iv_index,
@@ -696,118 +378,74 @@ int bt_mesh_net_decrypt(const u8_t key[16], struct os_mbuf *buf,
buf->om_len -= mic_len;
return bt_mesh_ccm_decrypt(key, nonce, &buf->om_data[7], buf->om_len - 7,
return bt_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)
static void create_app_nonce(uint8_t nonce[13],
const struct bt_mesh_app_crypto_ctx *ctx)
{
if (dev_key) {
if (ctx->dev_key) {
nonce[0] = 0x02;
} else {
nonce[0] = 0x01;
}
sys_put_be32((seq_num | ((u32_t)aszmic << 31)), &nonce[1]);
sys_put_be32((ctx->seq_num | ((uint32_t)ctx->aszmic << 31)), &nonce[1]);
sys_put_be16(src, &nonce[5]);
sys_put_be16(dst, &nonce[7]);
sys_put_be16(ctx->src, &nonce[5]);
sys_put_be16(ctx->dst, &nonce[7]);
sys_put_be32(iv_index, &nonce[9]);
sys_put_be32(ctx->iv_index, &nonce[9]);
}
static int mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, const u8_t *ad,
u16_t src, u16_t dst, u32_t seq_num, u32_t iv_index)
int bt_mesh_app_encrypt(const uint8_t key[16],
const struct bt_mesh_app_crypto_ctx *ctx,
struct os_mbuf *buf)
{
u8_t nonce[13];
int err;
uint8_t nonce[13];
BT_DBG("AppKey %s", bt_hex(key, 16));
BT_DBG("dev_key %u src 0x%04x dst 0x%04x", dev_key, src, dst);
BT_DBG("seq_num 0x%08x iv_index 0x%08x", (unsigned) seq_num,
(unsigned) iv_index);
BT_DBG("dev_key %u src 0x%04x dst 0x%04x", ctx->dev_key, ctx->src,
ctx->dst);
BT_DBG("seq_num 0x%08x iv_index 0x%08x", ctx->seq_num, ctx->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);
create_app_nonce(nonce, ctx);
BT_DBG("Nonce %s", bt_hex(nonce, 13));
return bt_mesh_ccm_encrypt(key, nonce, buf->om_data, buf->om_len, ad,
ad ? 16 : 0, buf->om_data,
APP_MIC_LEN(aszmic));
}
err = bt_ccm_encrypt(key, nonce, buf->om_data, buf->om_len, ctx->ad,
ctx->ad ? 16 : 0, buf->om_data,
APP_MIC_LEN(ctx->aszmic));
int bt_mesh_app_encrypt_in_place(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, const u8_t *ad, u16_t src,
u16_t dst, u32_t seq_num, u32_t iv_index)
{
int err;
err = mesh_app_encrypt(key, dev_key, aszmic, buf, ad, src, dst,
seq_num, iv_index);
if (!err) {
net_buf_simple_add(buf, APP_MIC_LEN(ctx->aszmic));
BT_DBG("Encr: %s", bt_hex(buf->om_data, buf->om_len));
}
return err;
}
int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, const u8_t *ad,
u16_t src, u16_t dst, u32_t seq_num, u32_t iv_index)
int bt_mesh_app_decrypt(const uint8_t key[16],
const struct bt_mesh_app_crypto_ctx *ctx,
struct os_mbuf *buf, struct os_mbuf *out)
{
uint8_t nonce[13];
int err;
err = mesh_app_encrypt(key, dev_key, aszmic, buf, ad, src, dst,
seq_num, iv_index);
if (!err) {
net_buf_simple_add(buf, APP_MIC_LEN(aszmic));
BT_DBG("Encr: %s", bt_hex(buf->om_data, buf->om_len));
}
return err;
}
static int mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, 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];
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);
create_app_nonce(nonce, ctx);
BT_DBG("AppKey %s", bt_hex(key, 16));
BT_DBG("Nonce %s", bt_hex(nonce, 13));
return bt_mesh_ccm_decrypt(key, nonce, buf->om_data, buf->om_len, ad,
ad ? 16 : 0, out->om_data,
APP_MIC_LEN(aszmic));
}
int bt_mesh_app_decrypt_in_place(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, const u8_t *ad, u16_t src,
u16_t dst, u32_t seq_num, u32_t iv_index)
{
return mesh_app_decrypt(key, dev_key, aszmic, buf, buf,
ad, src, dst, seq_num, iv_index);
}
int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, struct os_mbuf *out,
const u8_t *ad, u16_t src, u16_t dst, u32_t seq_num,
u32_t iv_index)
{
int err;
err = mesh_app_decrypt(key, dev_key, aszmic, buf, out,
ad, src, dst, seq_num, iv_index);
err = bt_ccm_decrypt(key, nonce, buf->om_data, buf->om_len, ctx->ad,
ctx->ad ? 16 : 0, out->om_data,
APP_MIC_LEN(ctx->aszmic));
if (!err) {
net_buf_simple_add(out, buf->om_len);
}
@@ -816,7 +454,7 @@ int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
}
/* reversed, 8-bit, poly=0x07 */
static const u8_t crc_table[256] = {
static const uint8_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,
@@ -858,9 +496,9 @@ static const u8_t crc_table[256] = {
0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf
};
u8_t bt_mesh_fcs_calc(const u8_t *data, u8_t data_len)
uint8_t bt_mesh_fcs_calc(const uint8_t *data, uint8_t data_len)
{
u8_t fcs = 0xff;
uint8_t fcs = 0xff;
while (data_len--) {
fcs = crc_table[fcs ^ *data++];
@@ -871,11 +509,11 @@ u8_t bt_mesh_fcs_calc(const u8_t *data, u8_t data_len)
return 0xff - fcs;
}
bool bt_mesh_fcs_check(struct os_mbuf *buf, u8_t received_fcs)
bool bt_mesh_fcs_check(struct os_mbuf *buf, uint8_t received_fcs)
{
const u8_t *data = buf->om_data;
u16_t data_len = buf->om_len;
u8_t fcs = 0xff;
const uint8_t *data = buf->om_data;
uint16_t data_len = buf->om_len;
uint8_t fcs = 0xff;
while (data_len--) {
fcs = crc_table[fcs ^ *data++];
@@ -884,10 +522,10 @@ bool bt_mesh_fcs_check(struct os_mbuf *buf, u8_t received_fcs)
return crc_table[fcs ^ received_fcs] == 0xcf;
}
int bt_mesh_virtual_addr(const u8_t virtual_label[16], u16_t *addr)
int bt_mesh_virtual_addr(const uint8_t virtual_label[16], uint16_t *addr)
{
u8_t salt[16];
u8_t tmp[16];
uint8_t salt[16];
uint8_t tmp[16];
int err;
err = bt_mesh_s1("vtad", salt);
@@ -905,21 +543,21 @@ int bt_mesh_virtual_addr(const u8_t virtual_label[16], u16_t *addr)
return 0;
}
int bt_mesh_prov_conf_salt(const u8_t conf_inputs[145], u8_t salt[16])
int bt_mesh_prov_conf_salt(const uint8_t conf_inputs[145], uint8_t salt[16])
{
const u8_t conf_salt_key[16] = { 0 };
const uint8_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])
int bt_mesh_prov_conf_key(const uint8_t dhkey[32], const uint8_t conf_salt[16],
uint8_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])
int bt_mesh_prov_conf(const uint8_t conf_key[16], const uint8_t rand[16],
const uint8_t auth[16], uint8_t conf[16])
{
struct bt_mesh_sg sg[] = { { rand, 16 }, { auth, 16 } };
@@ -930,23 +568,23 @@ int bt_mesh_prov_conf(const u8_t conf_key[16], const u8_t rand[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])
int bt_mesh_prov_decrypt(const uint8_t key[16], uint8_t nonce[13],
const uint8_t data[25 + 8], uint8_t out[25])
{
return bt_mesh_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8);
return bt_ccm_decrypt(key, nonce, data, 25, NULL, 0, out, 8);
}
int bt_mesh_prov_encrypt(const u8_t key[16], u8_t nonce[13],
const u8_t data[25], u8_t out[25 + 8])
int bt_mesh_prov_encrypt(const uint8_t key[16], uint8_t nonce[13],
const uint8_t data[25], uint8_t out[25 + 8])
{
return bt_mesh_ccm_encrypt(key, nonce, data, 25, NULL, 0, out, 8);
return bt_ccm_encrypt(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])
int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags,
const uint8_t net_id[8], uint32_t iv_index,
uint8_t auth[8])
{
u8_t msg[13], tmp[16];
uint8_t msg[13], tmp[16];
int err;
BT_DBG("BeaconKey %s", bt_hex(beacon_key, 16));

View File

@@ -15,81 +15,81 @@ struct bt_mesh_sg {
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]);
int bt_mesh_aes_cmac(const uint8_t key[16], struct bt_mesh_sg *sg,
size_t sg_len, uint8_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])
static inline int bt_mesh_aes_cmac_one(const uint8_t key[16], const void *m,
size_t len, uint8_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])
static inline bool bt_mesh_s1(const char *m, uint8_t salt[16])
{
const u8_t zero[16] = { 0 };
const uint8_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]);
int bt_mesh_k1(const uint8_t *ikm, size_t ikm_len, const uint8_t salt[16],
const char *info, uint8_t okm[16]);
#define bt_mesh_k1_str(ikm, ikm_len, salt_str, info, okm) \
({ \
const u8_t salt[16] = salt_str; \
const uint8_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_k2(const uint8_t n[16], const uint8_t *p, size_t p_len,
uint8_t net_id[1], uint8_t enc_key[16], uint8_t priv_key[16]);
int bt_mesh_k3(const u8_t n[16], u8_t out[8]);
int bt_mesh_k3(const uint8_t n[16], uint8_t out[8]);
int bt_mesh_k4(const u8_t n[16], u8_t out[1]);
int bt_mesh_k4(const uint8_t n[16], uint8_t out[1]);
int bt_mesh_id128(const u8_t n[16], const char *s, u8_t out[16]);
int bt_mesh_id128(const uint8_t n[16], const char *s, uint8_t out[16]);
static inline int bt_mesh_id_resolving_key(const u8_t net_key[16],
u8_t resolving_key[16])
static inline int bt_mesh_id_resolving_key(const uint8_t net_key[16],
uint8_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])
static inline int bt_mesh_identity_key(const uint8_t net_key[16],
uint8_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])
static inline int bt_mesh_beacon_key(const uint8_t net_key[16],
uint8_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[8], u32_t iv_index,
u8_t auth[8]);
int bt_mesh_beacon_auth(const uint8_t beacon_key[16], uint8_t flags,
const uint8_t net_id[8], uint32_t iv_index,
uint8_t auth[8]);
static inline int bt_mesh_app_id(const u8_t app_key[16], u8_t app_id[1])
static inline int bt_mesh_app_id(const uint8_t app_key[16], uint8_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])
static inline int bt_mesh_session_key(const uint8_t dhkey[32],
const uint8_t prov_salt[16],
uint8_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])
static inline int bt_mesh_prov_nonce(const uint8_t dhkey[32],
const uint8_t prov_salt[16],
uint8_t nonce[13])
{
u8_t tmp[16];
uint8_t tmp[16];
int err;
err = bt_mesh_k1(dhkey, 32, prov_salt, "prsn", tmp);
@@ -100,19 +100,19 @@ static inline int bt_mesh_prov_nonce(const u8_t dhkey[32],
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])
static inline int bt_mesh_dev_key(const uint8_t dhkey[32],
const uint8_t prov_salt[16],
uint8_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])
static inline int bt_mesh_prov_salt(const uint8_t conf_salt[16],
const uint8_t prov_rand[16],
const uint8_t dev_rand[16],
uint8_t prov_salt[16])
{
const u8_t prov_salt_key[16] = { 0 };
const uint8_t prov_salt_key[16] = { 0 };
struct bt_mesh_sg sg[] = {
{ conf_salt, 16 },
{ prov_rand, 16 },
@@ -122,49 +122,50 @@ static inline int bt_mesh_prov_salt(const u8_t conf_salt[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_obfuscate(uint8_t *pdu, uint32_t iv_index,
const uint8_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_encrypt(const uint8_t key[16], struct os_mbuf *buf,
uint32_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_net_decrypt(const uint8_t key[16], struct os_mbuf *buf,
uint32_t iv_index, bool proxy);
int bt_mesh_app_encrypt_in_place(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf*buf, const u8_t *ad, u16_t src,
u16_t dst, u32_t seq_num, u32_t iv_index);
struct bt_mesh_app_crypto_ctx {
bool dev_key;
uint8_t aszmic;
uint16_t src;
uint16_t dst;
uint32_t seq_num;
uint32_t iv_index;
const uint8_t *ad;
};
int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf*buf, const u8_t *ad,
u16_t src, u16_t dst, u32_t seq_num, u32_t iv_index);
int bt_mesh_app_encrypt(const uint8_t key[16],
const struct bt_mesh_app_crypto_ctx *ctx,
struct os_mbuf *buf);
int bt_mesh_app_decrypt_in_place(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, const u8_t *ad, u16_t src,
u16_t dst, u32_t seq_num, u32_t iv_index);
int bt_mesh_app_decrypt(const uint8_t key[16],
const struct bt_mesh_app_crypto_ctx *ctx,
struct os_mbuf *buf, struct os_mbuf *out);
int bt_mesh_app_decrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf*buf, struct os_mbuf*out,
const u8_t *ad, u16_t src, u16_t dst, u32_t seq_num,
u32_t iv_index);
uint8_t bt_mesh_fcs_calc(const uint8_t *data, uint8_t data_len);
u8_t bt_mesh_fcs_calc(const u8_t *data, u8_t data_len);
bool bt_mesh_fcs_check(struct os_mbuf *buf, uint8_t received_fcs);
bool bt_mesh_fcs_check(struct os_mbuf *buf, u8_t received_fcs);
int bt_mesh_virtual_addr(const uint8_t virtual_label[16], uint16_t *addr);
int bt_mesh_virtual_addr(const u8_t virtual_label[16], u16_t *addr);
int bt_mesh_prov_conf_salt(const uint8_t conf_inputs[145], uint8_t salt[16]);
int bt_mesh_prov_conf_salt(const u8_t conf_inputs[145], u8_t salt[16]);
int bt_mesh_prov_conf_key(const uint8_t dhkey[32], const uint8_t conf_salt[16],
uint8_t conf_key[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 uint8_t conf_key[16], const uint8_t rand[16],
const uint8_t auth[16], uint8_t conf[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 uint8_t key[16], uint8_t nonce[13],
const uint8_t data[25 + 8], uint8_t out[25]);
int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13],
const u8_t data[25 + 8], u8_t out[25]);
int bt_mesh_prov_encrypt(const u8_t key[16], u8_t nonce[13],
const u8_t data[25], u8_t out[25 + 8]);
int bt_mesh_prov_encrypt(const uint8_t key[16], uint8_t nonce[13],
const uint8_t data[25], uint8_t out[25 + 8]);
#endif

View File

@@ -115,57 +115,23 @@
#define STATUS_UNSPECIFIED 0x10
#define STATUS_INVALID_BINDING 0x11
enum {
BT_MESH_VA_CHANGED, /* Label information changed */
};
struct label {
u16_t ref;
u16_t addr;
u8_t uuid[16];
atomic_t flags[1];
};
void bt_mesh_cfg_reset(void);
void bt_mesh_heartbeat(u16_t src, u16_t dst, u8_t hops, u16_t feat);
void bt_mesh_attention(struct bt_mesh_model *model, u8_t time);
struct label *get_label(u16_t index);
u8_t *bt_mesh_label_uuid_get(u16_t addr);
struct bt_mesh_hb_pub *bt_mesh_hb_pub_get(void);
void bt_mesh_hb_pub_disable(void);
struct bt_mesh_cfg_srv *bt_mesh_cfg_get(void);
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);
void bt_mesh_subnet_del(struct bt_mesh_subnet *sub, bool store);
struct bt_mesh_app_key *bt_mesh_app_key_alloc(u16_t app_idx);
void bt_mesh_app_key_del(struct bt_mesh_app_key *key, bool store);
void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time);
static inline void key_idx_pack(struct os_mbuf *buf,
u16_t idx1, u16_t idx2)
uint16_t idx1, uint16_t idx2)
{
net_buf_simple_add_le16(buf, idx1 | ((idx2 & 0x00f) << 12));
net_buf_simple_add_u8(buf, idx2 >> 4);
}
static inline void key_idx_unpack(struct os_mbuf *buf,
u16_t *idx1, u16_t *idx2)
uint16_t *idx1, uint16_t *idx2)
{
*idx1 = sys_get_le16(&buf->om_data[0]) & 0xfff;
*idx2 = sys_get_le16(&buf->om_data[1]) >> 4;
net_buf_simple_pull(buf, 3);
net_buf_simple_pull_mem(buf, 3);
}
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -17,29 +17,29 @@ enum bt_mesh_friend_pdu_type {
BT_MESH_FRIEND_PDU_COMPLETE,
};
bool bt_mesh_friend_match(u16_t net_idx, u16_t addr);
bool bt_mesh_friend_match(uint16_t net_idx, uint16_t addr);
struct bt_mesh_friend *bt_mesh_friend_find(u16_t net_idx, u16_t lpn_addr,
struct bt_mesh_friend *bt_mesh_friend_find(uint16_t net_idx, uint16_t lpn_addr,
bool valid, bool established);
bool bt_mesh_friend_queue_has_space(u16_t net_idx, u16_t src, u16_t dst,
u64_t *seq_auth, u8_t seg_count);
bool bt_mesh_friend_queue_has_space(uint16_t net_idx, uint16_t src, uint16_t dst,
uint64_t *seq_auth, uint8_t seg_count);
void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, u8_t seg_count,
uint64_t *seq_auth, uint8_t seg_count,
struct os_mbuf *sbuf);
bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, u8_t seg_count,
uint64_t *seq_auth, uint8_t seg_count,
struct os_mbuf *sbuf);
void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
u16_t dst, u64_t *seq_auth);
void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, uint16_t src,
uint16_t dst, uint64_t *seq_auth);
void bt_mesh_friend_sec_update(u16_t net_idx);
void bt_mesh_friend_sec_update(uint16_t net_idx);
void bt_mesh_friend_clear_net_idx(u16_t net_idx);
void bt_mesh_friends_clear(void);
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);

View File

@@ -18,10 +18,10 @@
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#define MESH_LOG_MODULE BLE_MESH_LOG
#if MYNEWT_VAL(BLE_MESH)
#include "../include/mesh/glue.h"
#include "adv.h"
#ifndef MYNEWT
@@ -32,7 +32,7 @@
#include "base64/base64.h"
#endif
extern u8_t g_mesh_addr_type;
extern uint8_t g_mesh_addr_type;
#if MYNEWT_VAL(BLE_EXT_ADV)
/* Store configuration for different bearers */
@@ -46,8 +46,8 @@ 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;
static uint8_t curbuf;
const uint8_t *b = buf;
char *str;
int i;
@@ -239,6 +239,14 @@ net_buf_simple_add_be16(struct os_mbuf *om, uint16_t val)
ASSERT_NOT_CHAIN(om);
}
void
net_buf_simple_add_le24(struct os_mbuf *om, uint32_t val)
{
val = htole32(val);
os_mbuf_append(om, &val, 3);
ASSERT_NOT_CHAIN(om);
}
void
net_buf_simple_add_be32(struct os_mbuf *om, uint32_t val)
{
@@ -294,6 +302,22 @@ net_buf_simple_push_be16(struct os_mbuf *om, uint16_t val)
ASSERT_NOT_CHAIN(om);
}
void
net_buf_simple_push_be24(struct os_mbuf *om, uint32_t val)
{
uint8_t headroom = om->om_data - &om->om_databuf[om->om_pkthdr_len];
assert(headroom >= 3);
om->om_data -= 3;
put_be24(om->om_data, val);
om->om_len += 3;
if (om->om_pkthdr_len) {
OS_MBUF_PKTHDR(om)->omp_len += 3;
}
ASSERT_NOT_CHAIN(om);
}
void
net_buf_simple_push_u8(struct os_mbuf *om, uint8_t val)
{
@@ -358,7 +382,7 @@ k_fifo_is_empty(struct ble_npl_eventq *q)
return ble_npl_eventq_is_empty(q);
}
void * net_buf_get(struct ble_npl_eventq *fifo, s32_t t)
void * net_buf_get(struct ble_npl_eventq *fifo, int32_t t)
{
struct ble_npl_event *ev = ble_npl_eventq_get(fifo, 0);
@@ -409,6 +433,12 @@ k_delayed_work_init(struct k_delayed_work *w, ble_npl_event_fn *f)
#endif
}
bool
k_delayed_work_pending(struct k_delayed_work *w)
{
return ble_npl_callout_is_active(&w->work);
}
void
k_delayed_work_cancel(struct k_delayed_work *w)
{
@@ -465,7 +495,7 @@ int64_t k_uptime_get(void)
return ble_npl_time_ticks_to_ms32(ble_npl_time_get());
}
u32_t k_uptime_get_32(void)
uint32_t k_uptime_get_32(void)
{
return k_uptime_get();
}
@@ -484,7 +514,7 @@ static uint8_t priv[32];
static bool has_pub = false;
int
bt_dh_key_gen(const u8_t remote_pk[64], bt_dh_key_cb_t cb)
bt_dh_key_gen(const uint8_t remote_pk[64], bt_dh_key_cb_t cb)
{
uint8_t dh[32];
@@ -535,7 +565,7 @@ bt_pub_key_get(void)
}
static int
set_ad(const struct bt_data *ad, size_t ad_len, u8_t *buf, u8_t *buf_len)
set_ad(const struct bt_data *ad, size_t ad_len, uint8_t *buf, uint8_t *buf_len)
{
int i;
@@ -871,6 +901,52 @@ void net_buf_slist_merge_slist(struct net_buf_slist_t *list,
}
}
/** Memory slab methods */
extern void k_mem_slab_free(struct k_mem_slab *slab, void **mem)
{
**(char ***)mem = slab->free_list;
slab->free_list = *(char **)mem;
slab->num_used--;
}
extern int k_mem_slab_alloc(struct k_mem_slab *slab, void **mem)
{
int result;
if (slab->free_list != NULL) {
/* take a free block */
*mem = slab->free_list;
slab->free_list = *(char **)(slab->free_list);
slab->num_used++;
result = 0;
} else {
*mem = NULL;
result = -ENOMEM;
}
return result;
}
int create_free_list(struct k_mem_slab *slab)
{
uint32_t j;
char *p;
if(((slab->block_size | (uintptr_t)slab->buffer) &
(sizeof(void *) - 1)) != 0) {
return -EINVAL;
}
slab->free_list = NULL;
p = slab->buffer;
for (j = 0U; j < slab->num_blocks; j++) {
*(char **)p = slab->free_list;
slab->free_list = p;
p += slab->block_size;
}
return 0;
}
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
int settings_bytes_from_str(char *val_str, void *vp, int *len)
@@ -892,4 +968,4 @@ char *settings_str_from_bytes(const void *vp, int vp_len,
}
#endif /* MYNEWT_VAL(BLE_MESH_SETTINGS) */
#endif
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -23,15 +23,15 @@
#include "foundation.h"
#include "../include/mesh/health_cli.h"
static s32_t msg_timeout = K_SECONDS(5);
static int32_t msg_timeout = K_SECONDS(5);
static struct bt_mesh_health_cli *health_cli;
struct health_fault_param {
u16_t cid;
u8_t *expect_test_id;
u8_t *test_id;
u8_t *faults;
uint16_t cid;
uint8_t *expect_test_id;
uint8_t *test_id;
uint8_t *faults;
size_t *fault_count;
};
@@ -40,8 +40,8 @@ static void health_fault_status(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct health_fault_param *param;
u8_t test_id;
u16_t cid;
uint8_t test_id;
uint16_t cid;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
@@ -86,8 +86,8 @@ static void health_current_status(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct bt_mesh_health_cli *cli = model->user_data;
u8_t test_id;
u16_t cid;
uint8_t test_id;
uint16_t cid;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
ctx->net_idx, ctx->app_idx, ctx->addr, buf->om_len,
@@ -108,7 +108,7 @@ static void health_current_status(struct bt_mesh_model *model,
}
struct health_period_param {
u8_t *divisor;
uint8_t *divisor;
};
static void health_period_status(struct bt_mesh_model *model,
@@ -134,7 +134,7 @@ static void health_period_status(struct bt_mesh_model *model,
}
struct health_attention_param {
u8_t *attention;
uint8_t *attention;
};
static void health_attention_status(struct bt_mesh_model *model,
@@ -169,7 +169,7 @@ const struct bt_mesh_model_op bt_mesh_health_cli_op[] = {
BT_MESH_MODEL_OP_END,
};
static int cli_prepare(void *param, u32_t op)
static int cli_prepare(void *param, uint32_t op)
{
if (!health_cli) {
BT_ERR("No available Health Client context!");
@@ -204,12 +204,10 @@ static int cli_wait(void)
return err;
}
int bt_mesh_health_attention_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *attention)
int bt_mesh_health_attention_get(uint16_t addr, uint16_t app_idx, uint8_t *attention)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_GET, 0);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
@@ -239,12 +237,11 @@ done:
return err;
}
int bt_mesh_health_attention_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t attention, u8_t *updated_attention)
int bt_mesh_health_attention_set(uint16_t addr, uint16_t app_idx, uint8_t attention,
uint8_t *updated_attention)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_SET, 1);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
@@ -285,12 +282,10 @@ done:
return err;
}
int bt_mesh_health_period_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *divisor)
int bt_mesh_health_period_get(uint16_t addr, uint16_t app_idx, uint8_t *divisor)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_PERIOD_GET, 0);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
@@ -320,12 +315,11 @@ done:
return err;
}
int bt_mesh_health_period_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t divisor, u8_t *updated_divisor)
int bt_mesh_health_period_set(uint16_t addr, uint16_t app_idx, uint8_t divisor,
uint8_t *updated_divisor)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_PERIOD_SET, 1);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
@@ -366,13 +360,12 @@ done:
return err;
}
int bt_mesh_health_fault_test(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t test_id, u8_t *faults,
size_t *fault_count)
int bt_mesh_health_fault_test(uint16_t addr, uint16_t app_idx, uint16_t cid,
uint8_t test_id, uint8_t *faults,
size_t *fault_count)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_FAULT_TEST, 3);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
@@ -417,13 +410,12 @@ done:
return err;
}
int bt_mesh_health_fault_clear(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count)
int bt_mesh_health_fault_clear(uint16_t addr, uint16_t app_idx, uint16_t cid,
uint8_t *test_id, uint8_t *faults,
size_t *fault_count)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_FAULT_CLEAR, 2);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
@@ -467,13 +459,12 @@ done:
return err;
}
int bt_mesh_health_fault_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count)
int bt_mesh_health_fault_get(uint16_t addr, uint16_t app_idx, uint16_t cid,
uint8_t *test_id, uint8_t *faults,
size_t *fault_count)
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_FAULT_GET, 2);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = app_idx,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
@@ -507,12 +498,12 @@ done:
return err;
}
s32_t bt_mesh_health_cli_timeout_get(void)
int32_t bt_mesh_health_cli_timeout_get(void)
{
return msg_timeout;
}
void bt_mesh_health_cli_timeout_set(s32_t timeout)
void bt_mesh_health_cli_timeout_set(int32_t timeout)
{
msg_timeout = timeout;
}
@@ -525,6 +516,7 @@ int bt_mesh_health_cli_set(struct bt_mesh_model *model)
}
health_cli = model->user_data;
msg_timeout = 2 * MSEC_PER_SEC;
return 0;
}

View File

@@ -29,11 +29,11 @@
struct bt_mesh_health_srv *health_srv;
static void health_get_registered(struct bt_mesh_model *mod,
u16_t company_id,
uint16_t company_id,
struct os_mbuf *msg)
{
struct bt_mesh_health_srv *srv = mod->user_data;
u8_t *test_id;
uint8_t *test_id;
BT_DBG("Company ID 0x%04x", company_id);
@@ -43,7 +43,7 @@ static void health_get_registered(struct bt_mesh_model *mod,
net_buf_simple_add_le16(msg, company_id);
if (srv->cb && srv->cb->fault_get_reg) {
u8_t fault_count = net_buf_simple_tailroom(msg) - 4;
uint8_t fault_count = net_buf_simple_tailroom(msg) - 4;
int err;
err = srv->cb->fault_get_reg(mod, company_id, test_id,
@@ -66,9 +66,9 @@ static size_t health_get_current(struct bt_mesh_model *mod,
{
struct bt_mesh_health_srv *srv = mod->user_data;
const struct bt_mesh_comp *comp;
u8_t *test_id, *company_ptr;
u16_t company_id;
u8_t fault_count;
uint8_t *test_id, *company_ptr;
uint16_t company_id;
uint8_t fault_count;
int err;
bt_mesh_model_msg_init(msg, OP_HEALTH_CURRENT_STATUS);
@@ -106,7 +106,7 @@ static void health_fault_get(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
u16_t company_id;
uint16_t company_id;
company_id = net_buf_simple_pull_le16(buf);
@@ -126,7 +126,7 @@ static void health_fault_clear_unrel(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
uint16_t company_id;
company_id = net_buf_simple_pull_le16(buf);
@@ -143,7 +143,7 @@ static void health_fault_clear(struct bt_mesh_model *model,
{
struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
uint16_t company_id;
company_id = net_buf_simple_pull_le16(buf);
@@ -167,8 +167,8 @@ static void health_fault_test_unrel(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
u8_t test_id;
uint16_t company_id;
uint8_t test_id;
test_id = net_buf_simple_pull_u8(buf);
company_id = net_buf_simple_pull_le16(buf);
@@ -186,8 +186,8 @@ static void health_fault_test(struct bt_mesh_model *model,
{
struct os_mbuf *sdu = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_health_srv *srv = model->user_data;
u16_t company_id;
u8_t test_id;
uint16_t company_id;
uint8_t test_id;
BT_DBG("");
@@ -221,7 +221,7 @@ static void send_attention_status(struct bt_mesh_model *model,
{
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_STATUS, 1);
struct bt_mesh_health_srv *srv = model->user_data;
u8_t time;
uint8_t time;
time = k_delayed_work_remaining_get(&srv->attn_timer) / 1000;
BT_DBG("%u second%s", time, (time == 1) ? "" : "s");
@@ -250,7 +250,7 @@ static void attention_set_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
u8_t time;
uint8_t time;
time = net_buf_simple_pull_u8(buf);
@@ -299,7 +299,7 @@ static void health_period_set_unrel(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
u8_t period;
uint8_t period;
period = net_buf_simple_pull_u8(buf);
if (period > 15) {
@@ -391,10 +391,6 @@ static int health_srv_init(struct bt_mesh_model *model)
struct bt_mesh_health_srv *srv = model->user_data;
if (!srv) {
if (!bt_mesh_model_in_primary(model)) {
return 0;
}
BT_ERR("No Health Server context provided");
return -EINVAL;
}
@@ -422,7 +418,7 @@ const struct bt_mesh_model_cb bt_mesh_health_srv_cb = {
.init = health_srv_init,
};
void bt_mesh_attention(struct bt_mesh_model *model, u8_t time)
void bt_mesh_attention(struct bt_mesh_model *model, uint8_t time)
{
struct bt_mesh_health_srv *srv;

View File

@@ -0,0 +1,356 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#define MESH_LOG_MODULE BLE_MESH_HEARTBEAT_LOG
#include "mesh_priv.h"
#include "net.h"
#include "rpl.h"
#include "access.h"
#include "lpn.h"
#include "settings.h"
#include "transport.h"
#include "heartbeat.h"
#include "foundation.h"
#include "../include/mesh/glue.h"
struct bt_mesh_hb_cb hb_cb;
static struct bt_mesh_hb_pub pub;
static struct bt_mesh_hb_sub sub;
static struct k_delayed_work sub_timer;
static struct k_delayed_work pub_timer;
static int64_t sub_remaining(void)
{
if (sub.dst == BT_MESH_ADDR_UNASSIGNED) {
return 0U;
}
return k_delayed_work_remaining_get(&sub_timer) / MSEC_PER_SEC;
}
static void hb_publish_end_cb(int err, void *cb_data)
{
if (pub.period && pub.count > 1) {
k_delayed_work_submit(&pub_timer, K_SECONDS(pub.period));
}
if (pub.count != 0xffff) {
pub.count--;
}
}
static void notify_recv(uint8_t hops, uint16_t feat)
{
sub.remaining = sub_remaining();
if (hb_cb.recv != NULL) {
hb_cb.recv(&sub, hops, feat);
}
}
static void notify_sub_end(void)
{
sub.remaining = 0;
if (hb_cb.sub_end != NULL) {
hb_cb.sub_end(&sub);
}
}
static void sub_end(struct ble_npl_event *work)
{
notify_sub_end();
}
static int heartbeat_send(const struct bt_mesh_send_cb *cb, void *cb_data)
{
uint16_t feat = 0U;
struct __packed {
uint8_t init_ttl;
uint16_t feat;
} hb;
struct bt_mesh_msg_ctx ctx = {
.net_idx = pub.net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = pub.dst,
.send_ttl = pub.ttl,
};
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(pub.net_idx),
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
.xmit = bt_mesh_net_transmit_get(),
};
/* Do nothing if heartbeat publication is not enabled */
if (pub.dst == BT_MESH_ADDR_UNASSIGNED) {
return 0U;
}
hb.init_ttl = pub.ttl;
if (bt_mesh_relay_get() == BT_MESH_RELAY_ENABLED) {
feat |= BT_MESH_FEAT_RELAY;
}
if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) {
feat |= BT_MESH_FEAT_PROXY;
}
if (bt_mesh_friend_get() == BT_MESH_FRIEND_ENABLED) {
feat |= BT_MESH_FEAT_FRIEND;
}
if (bt_mesh_lpn_established()) {
feat |= BT_MESH_FEAT_LOW_POWER;
}
hb.feat = sys_cpu_to_be16(feat);
BT_DBG("InitTTL %u feat 0x%04x", pub.ttl, feat);
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb),
cb, cb_data);
}
static void hb_publish_start_cb(uint16_t duration, int err, void *cb_data)
{
if (err) {
hb_publish_end_cb(err, cb_data);
}
}
static void hb_publish(struct ble_npl_event *work)
{
static const struct bt_mesh_send_cb publish_cb = {
.start = hb_publish_start_cb,
.end = hb_publish_end_cb,
};
struct bt_mesh_subnet *sub;
int err;
BT_DBG("hb_pub.count: %u", pub.count);
sub = bt_mesh_subnet_get(pub.net_idx);
if (!sub) {
BT_ERR("No matching subnet for idx 0x%02x", pub.net_idx);
pub.dst = BT_MESH_ADDR_UNASSIGNED;
return;
}
if (pub.count == 0U) {
return;
}
err = heartbeat_send(&publish_cb, NULL);
if (err) {
hb_publish_end_cb(err, NULL);
}
}
int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
{
uint8_t init_ttl, hops;
uint16_t feat;
if (buf->om_len < 3) {
BT_ERR("Too short heartbeat message");
return -EINVAL;
}
init_ttl = (net_buf_simple_pull_u8(buf) & 0x7f);
feat = net_buf_simple_pull_be16(buf);
hops = (init_ttl - rx->ctx.recv_ttl + 1);
if (rx->ctx.addr != sub.src || rx->ctx.recv_dst != sub.dst) {
BT_DBG("No subscription for received heartbeat");
return 0;
}
if (!k_delayed_work_pending(&sub_timer)) {
BT_DBG("Heartbeat subscription period expired");
return 0;
}
sub.min_hops = MIN(sub.min_hops, hops);
sub.max_hops = MAX(sub.max_hops, hops);
if (sub.count < 0xffff) {
sub.count++;
}
BT_DBG("src 0x%04x TTL %u InitTTL %u (%u hop%s) feat 0x%04x",
rx->ctx.addr, rx->ctx.recv_ttl, init_ttl, hops,
(hops == 1U) ? "" : "s", feat);
notify_recv(hops, feat);
return 0;
}
static void pub_disable(void)
{
BT_DBG("");
pub.dst = BT_MESH_ADDR_UNASSIGNED;
pub.count = 0U;
pub.ttl = 0U;
pub.period = 0U;
k_delayed_work_cancel(&pub_timer);
}
uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *new_pub)
{
if (!new_pub || new_pub->dst == BT_MESH_ADDR_UNASSIGNED) {
pub_disable();
if (IS_ENABLED(CONFIG_BT_SETTINGS) &&
bt_mesh_is_provisioned()) {
bt_mesh_store_hb_pub();
}
return STATUS_SUCCESS;
}
if (!bt_mesh_subnet_get(new_pub->net_idx)) {
BT_ERR("Unknown NetKey 0x%04x", new_pub->net_idx);
return STATUS_INVALID_NETKEY;
}
new_pub->feat &= BT_MESH_FEAT_SUPPORTED;
pub = *new_pub;
if (!bt_mesh_is_provisioned()) {
return STATUS_SUCCESS;
}
/* The first Heartbeat message shall be published as soon as possible
* after the Heartbeat Publication Period state has been configured for
* periodic publishing.
*/
if (pub.period && pub.count) {
k_delayed_work_submit(&pub_timer, K_NO_WAIT);
} else {
k_delayed_work_cancel(&pub_timer);
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_hb_pub();
}
return STATUS_SUCCESS;
}
void bt_mesh_hb_pub_get(struct bt_mesh_hb_pub *get)
{
*get = pub;
}
uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period)
{
if (src != BT_MESH_ADDR_UNASSIGNED && !BT_MESH_ADDR_IS_UNICAST(src)) {
BT_WARN("Prohibited source address");
return STATUS_INVALID_ADDRESS;
}
if (BT_MESH_ADDR_IS_VIRTUAL(dst) || BT_MESH_ADDR_IS_RFU(dst) ||
(BT_MESH_ADDR_IS_UNICAST(dst) && dst != bt_mesh_primary_addr())) {
BT_WARN("Prohibited destination address");
return STATUS_INVALID_ADDRESS;
}
if (period > (1U << 16)) {
BT_WARN("Prohibited subscription period %u s", period);
return STATUS_CANNOT_SET;
}
/* Only an explicit address change to unassigned should trigger clearing
* of the values according to MESH/NODE/CFG/HBS/BV-02-C.
*/
if (src == BT_MESH_ADDR_UNASSIGNED || dst == BT_MESH_ADDR_UNASSIGNED) {
sub.src = BT_MESH_ADDR_UNASSIGNED;
sub.dst = BT_MESH_ADDR_UNASSIGNED;
sub.min_hops = 0U;
sub.max_hops = 0U;
sub.count = 0U;
sub.period = sub.period - sub_remaining();
k_delayed_work_cancel(&sub_timer);
notify_sub_end();
} else if (period) {
sub.src = src;
sub.dst = dst;
sub.min_hops = BT_MESH_TTL_MAX;
sub.max_hops = 0U;
sub.count = 0U;
sub.period = period;
k_delayed_work_submit(&sub_timer, K_SECONDS(period));
} else {
/* Clearing the period should stop heartbeat subscription
* without clearing the parameters, so we can still read them.
*/
sub.period = sub.period - sub_remaining();
k_delayed_work_cancel(&sub_timer);
notify_sub_end();
}
return STATUS_SUCCESS;
}
void bt_mesh_hb_sub_get(struct bt_mesh_hb_sub *get)
{
*get = sub;
get->remaining = sub_remaining();
}
void bt_mesh_hb_feature_changed(uint16_t features)
{
if (pub.dst == BT_MESH_ADDR_UNASSIGNED) {
return;
}
if (!(pub.feat & features)) {
return;
}
heartbeat_send(NULL, NULL);
}
void bt_mesh_hb_init(void)
{
pub.net_idx = BT_MESH_KEY_UNUSED;
k_delayed_work_init(&pub_timer, hb_publish);
k_delayed_work_init(&sub_timer, sub_end);
}
void bt_mesh_hb_start(void)
{
if (pub.count && pub.period) {
BT_DBG("Starting heartbeat publication");
k_delayed_work_submit(&pub_timer, K_NO_WAIT);
}
}
void bt_mesh_hb_suspend(void)
{
k_delayed_work_cancel(&pub_timer);
}
void bt_mesh_hb_resume(void)
{
if (pub.period && pub.count) {
BT_DBG("Starting heartbeat publication");
k_delayed_work_submit(&pub_timer, K_NO_WAIT);
}
}
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,40 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "../include/mesh/heartbeat.h"
static inline uint16_t bt_mesh_hb_pwr2(uint8_t val)
{
if (!val) {
return 0x0000;
} else if (val == 0xff || val == 0x11) {
return 0xffff;
} else {
return (1 << (val - 1));
}
}
static inline uint8_t bt_mesh_hb_log(uint32_t val)
{
if (!val) {
return 0x00;
} else if (val == 0xffff) {
return 0xff;
} else {
return 32 - __builtin_clz(val);
}
}
void bt_mesh_hb_init(void);
void bt_mesh_hb_start(void);
void bt_mesh_hb_suspend(void);
void bt_mesh_hb_resume(void);
int bt_mesh_hb_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf);
void bt_mesh_hb_feature_changed(uint16_t features);
uint8_t bt_mesh_hb_pub_set(struct bt_mesh_hb_pub *hb_pub);
uint8_t bt_mesh_hb_sub_set(uint16_t src, uint16_t dst, uint32_t period);

View File

@@ -7,52 +7,52 @@
#include "light_model.h"
static u8_t gen_onoff_state;
static s16_t gen_level_state;
static uint8_t gen_onoff_state;
static int16_t gen_level_state;
static void update_light_state(void)
{
console_printf("Light state: onoff=%d lvl=0x%04x\n", gen_onoff_state, (u16_t)gen_level_state);
console_printf("Light state: onoff=%d lvl=0x%04x\n", gen_onoff_state, (uint16_t)gen_level_state);
}
int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state)
int light_model_gen_onoff_get(struct bt_mesh_model *model, uint8_t *state)
{
*state = gen_onoff_state;
return 0;
}
int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state)
int light_model_gen_onoff_set(struct bt_mesh_model *model, uint8_t state)
{
gen_onoff_state = state;
update_light_state();
return 0;
}
int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level)
int light_model_gen_level_get(struct bt_mesh_model *model, int16_t *level)
{
*level = gen_level_state;
return 0;
}
int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level)
int light_model_gen_level_set(struct bt_mesh_model *model, int16_t level)
{
gen_level_state = level;
if ((u16_t)gen_level_state > 0x0000) {
if ((uint16_t)gen_level_state > 0x0000) {
gen_onoff_state = 1;
}
if ((u16_t)gen_level_state == 0x0000) {
if ((uint16_t)gen_level_state == 0x0000) {
gen_onoff_state = 0;
}
update_light_state();
return 0;
}
int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness)
int light_model_light_lightness_get(struct bt_mesh_model *model, int16_t *lightness)
{
return light_model_gen_level_get(model, lightness);
}
int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness)
int light_model_light_lightness_set(struct bt_mesh_model *model, int16_t lightness)
{
return light_model_gen_level_set(model, lightness);
}

View File

@@ -9,11 +9,11 @@
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#include "../include/mesh/mesh.h"
int light_model_gen_onoff_get(struct bt_mesh_model *model, u8_t *state);
int light_model_gen_onoff_set(struct bt_mesh_model *model, u8_t state);
int light_model_gen_level_get(struct bt_mesh_model *model, s16_t *level);
int light_model_gen_level_set(struct bt_mesh_model *model, s16_t level);
int light_model_light_lightness_get(struct bt_mesh_model *model, s16_t *lightness);
int light_model_light_lightness_set(struct bt_mesh_model *model, s16_t lightness);
int light_model_gen_onoff_get(struct bt_mesh_model *model, uint8_t *state);
int light_model_gen_onoff_set(struct bt_mesh_model *model, uint8_t state);
int light_model_gen_level_get(struct bt_mesh_model *model, int16_t *level);
int light_model_gen_level_set(struct bt_mesh_model *model, int16_t level);
int light_model_light_lightness_get(struct bt_mesh_model *model, int16_t *lightness);
int light_model_light_lightness_set(struct bt_mesh_model *model, int16_t lightness);
#endif

View File

@@ -21,6 +21,7 @@
#include "adv.h"
#include "net.h"
#include "transport.h"
#include "heartbeat.h"
#include "access.h"
#include "beacon.h"
#include "foundation.h"
@@ -44,27 +45,33 @@
#define POLL_RETRY_TIMEOUT K_MSEC(100)
#define REQ_RETRY_DURATION(lpn) (4 * (LPN_RECV_DELAY + (lpn)->adv_duration + \
(lpn)->recv_win + POLL_RETRY_TIMEOUT))
#define REQ_RETRY_DURATION(lpn) (LPN_RECV_DELAY + (lpn)->adv_duration + \
(lpn)->recv_win + POLL_RETRY_TIMEOUT)
#define POLL_TIMEOUT_INIT (MYNEWT_VAL(BLE_MESH_LPN_INIT_POLL_TIMEOUT) * 100)
#define POLL_TIMEOUT_MAX(lpn) ((MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT) * 100) - \
REQ_RETRY_DURATION(lpn))
#define REQ_ATTEMPTS(lpn) (POLL_TIMEOUT_MAX(lpn) < K_SECONDS(3) ? 2 : 4)
#define CLEAR_ATTEMPTS 2
#define POLL_TIMEOUT (MYNEWT_VAL(BLE_MESH_LPN_RECV_DELAY) * 100)
#define REQ_ATTEMPTS_MAX 6
#define REQ_ATTEMPTS(lpn) MIN(REQ_ATTEMPTS_MAX, \
POLL_TIMEOUT / REQ_RETRY_DURATION(lpn))
#define POLL_TIMEOUT_MAX(lpn) (POLL_TIMEOUT - \
(REQ_ATTEMPTS(lpn) * REQ_RETRY_DURATION(lpn)))
#define CLEAR_ATTEMPTS 3
#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 POLL_TO(to) { (uint8_t)((to) >> 16), (uint8_t)((to) >> 8), (uint8_t)(to) }
#define LPN_POLL_TO POLL_TO(MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT))
/* 2 transmissions, 20ms interval */
#define POLL_XMIT BT_MESH_TRANSMIT(1, 20)
static void (*lpn_cb)(u16_t friend_addr, bool established);
static void (*lpn_cb)(uint16_t friend_addr, bool established);
#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
static const char *state2str(int state)
@@ -147,10 +154,7 @@ static void friend_clear_sent(int err, void *user_data)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
/* We're switching away from Low Power behavior, so permanently
* enable scanning.
*/
bt_mesh_scan_enable();
/* Scanning will enable if lpn state still enabled */
lpn->req_attempts++;
@@ -172,31 +176,30 @@ static const struct bt_mesh_send_cb clear_sent_cb = {
static int send_friend_clear(void)
{
struct bt_mesh_msg_ctx ctx = {
.net_idx = bt_mesh.sub[0].net_idx,
.net_idx = bt_mesh.lpn.sub->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],
.sub = bt_mesh.lpn.sub,
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
.xmit = bt_mesh_net_transmit_get(),
};
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),
.lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.lpn_counter),
};
BT_DBG("");
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req,
sizeof(req), NULL, &clear_sent_cb, NULL);
sizeof(req), &clear_sent_cb, NULL);
}
static void clear_friendship(bool force, bool disable)
{
struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get();
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
BT_DBG("force %u disable %u", force, disable);
@@ -212,8 +215,6 @@ static void clear_friendship(bool force, bool disable)
k_delayed_work_cancel(&lpn->timer);
friend_cred_del(bt_mesh.sub[0].net_idx, lpn->frnd);
if (lpn->clear_success) {
lpn->old_friend = BT_MESH_ADDR_UNASSIGNED;
} else {
@@ -233,6 +234,7 @@ static void clear_friendship(bool force, bool disable)
lpn->sent_req = 0;
lpn->established = 0;
lpn->clear_success = 0;
lpn->sub = NULL;
group_zero(lpn->added);
group_zero(lpn->pending);
@@ -244,9 +246,7 @@ static void clear_friendship(bool force, bool disable)
*/
lpn->groups_changed = 1;
if (cfg->hb_pub.feat & BT_MESH_FEAT_LOW_POWER) {
bt_mesh_heartbeat_send();
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER);
if (disable) {
lpn_set_state(BT_MESH_LPN_DISABLED);
@@ -257,7 +257,7 @@ static void clear_friendship(bool force, bool disable)
k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT);
}
static void friend_req_sent(u16_t duration, int err, void *user_data)
static void friend_req_sent(uint16_t duration, int err, void *user_data)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
@@ -286,33 +286,43 @@ static int send_friend_req(struct bt_mesh_lpn *lpn)
{
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(),
.xmit = POLL_XMIT,
};
lpn->lpn_counter++;
struct bt_mesh_ctl_friend_req req = {
.criteria = LPN_CRITERIA,
.recv_delay = LPN_RECV_DELAY,
.poll_to = LPN_POLL_TO,
.prev_addr = lpn->old_friend,
.prev_addr = sys_cpu_to_be16(lpn->old_friend),
.num_elem = comp->elem_count,
.lpn_counter = sys_cpu_to_be16(lpn->counter),
.lpn_counter = sys_cpu_to_be16(lpn->lpn_counter),
};
BT_DBG("");
lpn->sub = bt_mesh_subnet_next(NULL);
if (!lpn->sub) {
BT_ERR("No subnets, can't start LPN mode");
return -ENOENT;
}
ctx.net_idx = lpn->sub->net_idx;
tx.sub = lpn->sub;
return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req,
sizeof(req), NULL, &friend_req_sent_cb, NULL);
sizeof(req), &friend_req_sent_cb, NULL);
}
static void req_sent(u16_t duration, int err, void *user_data)
static void req_sent(uint16_t duration, int err, void *user_data)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
@@ -339,6 +349,7 @@ static void req_sent(u16_t duration, int err, void *user_data)
k_delayed_work_submit(&lpn->timer,
LPN_RECV_DELAY - SCAN_LATENCY);
} else {
lpn_set_state(BT_MESH_LPN_WAIT_UPDATE);
k_delayed_work_submit(&lpn->timer,
LPN_RECV_DELAY + duration +
lpn->recv_win);
@@ -352,20 +363,20 @@ static const struct bt_mesh_send_cb req_sent_cb = {
static int send_friend_poll(void)
{
struct bt_mesh_msg_ctx ctx = {
.net_idx = bt_mesh.sub[0].net_idx,
.net_idx = bt_mesh.lpn.sub->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],
.sub = bt_mesh.lpn.sub,
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
.xmit = POLL_XMIT,
.friend_cred = true,
};
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
u8_t fsn = lpn->fsn;
uint8_t fsn = lpn->fsn;
int err;
BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req);
@@ -379,7 +390,7 @@ static int send_friend_poll(void)
}
err = bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_POLL, &fsn, 1,
NULL, &req_sent_cb, NULL);
&req_sent_cb, NULL);
if (err == 0) {
lpn->pending_poll = 0;
lpn->sent_req = TRANS_CTL_OP_FRIEND_POLL;
@@ -479,14 +490,22 @@ void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx)
send_friend_poll();
}
static int friend_cred_create(struct bt_mesh_net_cred *cred,
const uint8_t key[16])
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
return bt_mesh_friend_cred_create(cred, bt_mesh_primary_addr(),
lpn->frnd, lpn->lpn_counter,
lpn->frnd_counter, key);
}
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 friend_cred *cred;
u16_t frnd_counter;
uint16_t frnd_counter;
int err;
if (buf->om_len < sizeof(*msg)) {
@@ -510,16 +529,24 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
msg->recv_win, msg->queue_size, msg->sub_list_size, msg->rssi,
frnd_counter);
lpn->frnd_counter = frnd_counter;
lpn->frnd = rx->ctx.addr;
cred = friend_cred_create(sub, lpn->frnd, lpn->counter, frnd_counter);
if (!cred) {
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
return -ENOMEM;
/* Create friend credentials for each of the valid keys in the
* friendship subnet:
*/
for (int i = 0; i < ARRAY_SIZE(lpn->cred); i++) {
if (!lpn->sub->keys[i].valid) {
continue;
}
err = friend_cred_create(&lpn->cred[i], lpn->sub->keys[i].net);
if (err) {
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;
@@ -527,15 +554,13 @@ int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
err = send_friend_poll();
if (err) {
friend_cred_clear(cred);
lpn->sub = NULL;
lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
lpn->recv_win = 0;
lpn->queue_size = 0;
return err;
}
lpn->counter++;
return 0;
}
@@ -544,7 +569,7 @@ int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx,
{
struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->om_data;
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
u16_t addr, counter;
uint16_t addr, counter;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Clear Confirm");
@@ -561,7 +586,7 @@ int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx,
BT_DBG("LPNAddress 0x%04x LPNCounter 0x%04x", addr, counter);
if (addr != bt_mesh_primary_addr() || counter != lpn->counter) {
if (addr != bt_mesh_primary_addr() || counter != lpn->lpn_counter) {
BT_WARN("Invalid parameters in Friend Clear Confirm");
return 0;
}
@@ -572,10 +597,10 @@ int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx,
return 0;
}
static void lpn_group_add(u16_t group)
static void lpn_group_add(uint16_t group)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
u16_t *free_slot = NULL;
uint16_t *free_slot = NULL;
int i;
for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) {
@@ -598,7 +623,7 @@ static void lpn_group_add(u16_t group)
lpn->groups_changed = 1;
}
static void lpn_group_del(u16_t group)
static void lpn_group_del(uint16_t group)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
int i;
@@ -629,18 +654,18 @@ static inline int group_popcount(atomic_t *target)
#endif
}
static bool sub_update(u8_t op)
static bool sub_update(uint8_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,
.net_idx = lpn->sub->net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = lpn->frnd,
.send_ttl = 0,
};
struct bt_mesh_net_tx tx = {
.sub = &bt_mesh.sub[0],
.sub = lpn->sub,
.ctx = &ctx,
.src = bt_mesh_primary_addr(),
.xmit = POLL_XMIT,
@@ -690,8 +715,8 @@ static bool sub_update(u8_t op)
req.xact = lpn->xact_next++;
if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2, NULL,
&req_sent_cb, NULL) < 0) {
if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2,
&req_sent_cb, NULL) < 0) {
group_zero(lpn->pending);
return false;
}
@@ -713,7 +738,7 @@ static void update_timeout(struct bt_mesh_lpn *lpn)
bt_mesh_scan_disable();
}
if (lpn->req_attempts < 6) {
if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) {
BT_WARN("Retrying first Friend Poll");
lpn->sent_req = 0;
if (send_friend_poll() == 0) {
@@ -761,14 +786,14 @@ static void lpn_timeout(struct ble_npl_event *work)
if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
bt_mesh_scan_disable();
}
lpn->counter++;
lpn->lpn_counter++;
lpn_set_state(BT_MESH_LPN_ENABLED);
lpn->sent_req = 0U;
k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT);
break;
case BT_MESH_LPN_ESTABLISHED:
if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) {
u8_t req = lpn->sent_req;
uint8_t req = lpn->sent_req;
lpn->sent_req = 0;
@@ -802,7 +827,7 @@ static void lpn_timeout(struct ble_npl_event *work)
}
}
void bt_mesh_lpn_group_add(u16_t group)
void bt_mesh_lpn_group_add(uint16_t group)
{
BT_DBG("group 0x%04x", group);
@@ -815,7 +840,7 @@ void bt_mesh_lpn_group_add(u16_t group)
sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
}
void bt_mesh_lpn_group_del(u16_t *groups, size_t group_count)
void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count)
{
int i;
@@ -833,7 +858,7 @@ void bt_mesh_lpn_group_del(u16_t *groups, size_t group_count)
sub_update(TRANS_CTL_OP_FRIEND_SUB_REM);
}
static s32_t poll_timeout(struct bt_mesh_lpn *lpn)
static int32_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()) {
@@ -910,7 +935,9 @@ int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx,
}
if (!lpn->sent_req) {
k_delayed_work_submit(&lpn->timer, poll_timeout(lpn));
int32_t timeout = poll_timeout(lpn);
k_delayed_work_submit(&lpn->timer, K_MSEC(timeout));
}
return 0;
@@ -922,7 +949,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
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;
uint32_t iv_index;
if (buf->om_len < sizeof(*msg)) {
BT_WARN("Too short Friend Update");
@@ -946,8 +973,6 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
}
if (!lpn->established) {
struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get();
/* 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
@@ -962,9 +987,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
BT_INFO("Friendship established with 0x%04x", lpn->frnd);
if (cfg->hb_pub.feat & BT_MESH_FEAT_LOW_POWER) {
bt_mesh_heartbeat_send();
}
bt_mesh_hb_feature_changed(BT_MESH_FEAT_LOW_POWER);
if (lpn_cb) {
lpn_cb(lpn->frnd, true);
@@ -982,11 +1005,7 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
BT_DBG("flags 0x%02x iv_index 0x%08x md %u", msg->flags,
(unsigned) 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_kr_update(sub, BT_MESH_KEY_REFRESH(msg->flags), rx->new_key);
bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(msg->flags));
if (lpn->groups_changed) {
@@ -1004,7 +1023,9 @@ int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
}
if (!lpn->sent_req) {
k_delayed_work_submit(&lpn->timer, poll_timeout(lpn));
int32_t timeout = poll_timeout(lpn);
k_delayed_work_submit(&lpn->timer, K_MSEC(timeout));
}
return 0;
@@ -1021,17 +1042,41 @@ int bt_mesh_lpn_poll(void)
return send_friend_poll();
}
void bt_mesh_lpn_set_cb(void (*cb)(u16_t friend_addr, bool established))
void bt_mesh_lpn_set_cb(void (*cb)(uint16_t friend_addr, bool established))
{
lpn_cb = cb;
}
static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
{
switch (evt) {
case BT_MESH_KEY_DELETED:
if (sub == bt_mesh.lpn.sub) {
BT_DBG("NetKey deleted");
clear_friendship(true, false);
}
break;
case BT_MESH_KEY_UPDATED:
BT_DBG("NetKey updated");
friend_cred_create(&bt_mesh.lpn.cred[1], sub->keys[1].net);
break;
default:
break;
}
}
int bt_mesh_lpn_init(void)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
if (!bt_mesh_subnet_cb_list[2]) {
bt_mesh_subnet_cb_list[2] = subnet_evt;
}
BT_DBG("");
lpn->groups_changed = 0;
k_delayed_work_init(&lpn->timer, lpn_timeout);
if (lpn->state == BT_MESH_LPN_ENABLED) {

View File

@@ -28,7 +28,7 @@ static inline bool bt_mesh_lpn_established(void)
#endif
}
static inline bool bt_mesh_lpn_match(u16_t addr)
static inline bool bt_mesh_lpn_match(uint16_t addr)
{
#if (MYNEWT_VAL(BLE_MESH_LOW_POWER))
if (bt_mesh_lpn_established()) {
@@ -58,8 +58,8 @@ static inline bool bt_mesh_lpn_timer(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_group_add(uint16_t group);
void bt_mesh_lpn_group_del(uint16_t *groups, size_t group_count);
void bt_mesh_lpn_disable(bool force);

View File

@@ -20,7 +20,12 @@
#include "adv.h"
#include "prov.h"
#include "provisioner.h"
#include "net.h"
#include "subnet.h"
#include "app_keys.h"
#include "rpl.h"
#include "cfg.h"
#include "beacon.h"
#include "lpn.h"
#include "friend.h"
@@ -28,16 +33,18 @@
#include "access.h"
#include "foundation.h"
#include "proxy.h"
#include "heartbeat.h"
#include "shell.h"
#include "mesh_priv.h"
#include "settings.h"
u8_t g_mesh_addr_type;
uint8_t g_mesh_addr_type;
static struct ble_gap_event_listener mesh_event_listener;
int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
u8_t flags, u32_t iv_index, u16_t addr,
const u8_t dev_key[16])
int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx,
uint8_t flags, uint32_t iv_index, uint16_t addr,
const uint8_t dev_key[16])
{
bool pb_gatt_enabled;
int err;
@@ -60,6 +67,53 @@ int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
pb_gatt_enabled = false;
}
/*
* FIXME:
* Should net_key and iv_index be over-ridden?
*/
if (IS_ENABLED(BLE_MESH_CDB)) {
const struct bt_mesh_comp *comp;
const struct bt_mesh_prov *prov;
struct bt_mesh_cdb_node *node;
if (!atomic_test_bit(bt_mesh_cdb.flags,
BT_MESH_CDB_VALID)) {
BT_ERR("No valid network");
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
return -EINVAL;
}
comp = bt_mesh_comp_get();
if (comp == NULL) {
BT_ERR("Failed to get node composition");
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
return -EINVAL;
}
if (!bt_mesh_cdb_subnet_get(net_idx)) {
BT_ERR("No subnet with idx %d", net_idx);
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
return -ENOENT;
}
prov = bt_mesh_prov_get();
node = bt_mesh_cdb_node_alloc(prov->uuid, addr,
comp->elem_count, net_idx);
if (node == NULL) {
BT_ERR("Failed to allocate database node");
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
return -ENOMEM;
}
addr = node->addr;
iv_index = bt_mesh_cdb.iv_index;
memcpy(node->dev_key, dev_key, 16);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb_node(node);
}
}
err = bt_mesh_net_create(net_idx, flags, net_key, iv_index);
if (err) {
atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID);
@@ -77,20 +131,18 @@ int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
memcpy(bt_mesh.dev_key, dev_key, 16);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
BT_DBG("Storing network information persistently");
bt_mesh_store_net();
bt_mesh_store_subnet(&bt_mesh.sub[0]);
bt_mesh_store_iv(false);
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) &&
IS_ENABLED(CONFIG_BT_MESH_LPN_SUB_ALL_NODES_ADDR)) {
bt_mesh_lpn_group_add(BT_MESH_ADDR_ALL_NODES);
}
bt_mesh_net_start();
bt_mesh_start();
return 0;
}
int bt_mesh_provision_adv(const u8_t uuid[16], u16_t net_idx, u16_t addr,
u8_t attention_duration)
int bt_mesh_provision_adv(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
uint8_t attention_duration)
{
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
return -EINVAL;
@@ -124,25 +176,30 @@ void bt_mesh_reset(void)
bt_mesh_cfg_reset();
bt_mesh_rx_reset();
bt_mesh_tx_reset();
bt_mesh_trans_reset();
bt_mesh_app_keys_reset();
bt_mesh_net_keys_reset();
bt_mesh_net_loopback_clear(BT_MESH_KEY_ANY);
if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
if (IS_ENABLED(CONFIG_BT_MESH_LPN_SUB_ALL_NODES_ADDR)) {
uint16_t group = BT_MESH_ADDR_ALL_NODES;
bt_mesh_lpn_group_del(&group, 1);
}
bt_mesh_lpn_disable(true);
}
if ((MYNEWT_VAL(BLE_MESH_FRIEND))) {
bt_mesh_friend_clear_net_idx(BT_MESH_KEY_ANY);
bt_mesh_friends_clear();
}
if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY))) {
bt_mesh_proxy_gatt_disable();
}
if ((MYNEWT_VAL(BLE_MESH_PB_GATT))) {
bt_mesh_proxy_prov_enable();
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_clear_net();
}
@@ -164,55 +221,6 @@ bool bt_mesh_is_provisioned(void)
return atomic_test_bit(bt_mesh.flags, BT_MESH_VALID);
}
int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers)
{
if (bt_mesh_is_provisioned()) {
return -EALREADY;
}
char uuid_buf[BLE_UUID_STR_LEN];
const struct bt_mesh_prov *prov = bt_mesh_prov_get();
ble_uuid_t *uuid = BLE_UUID128_DECLARE();
memcpy(BLE_UUID128(uuid)->value, prov->uuid, 16);
BT_INFO("Device UUID: %s", ble_uuid_to_str(uuid, uuid_buf));
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&
(bearers & BT_MESH_PROV_ADV)) {
/* Make sure we're scanning for provisioning inviations */
bt_mesh_scan_enable();
/* Enable unprovisioned beacon sending */
bt_mesh_beacon_enable();
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
(bearers & BT_MESH_PROV_GATT)) {
bt_mesh_proxy_prov_enable();
bt_mesh_adv_update();
}
return 0;
}
int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers)
{
if (bt_mesh_is_provisioned()) {
return -EALREADY;
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&
(bearers & BT_MESH_PROV_ADV)) {
bt_mesh_beacon_disable();
bt_mesh_scan_disable();
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
(bearers & BT_MESH_PROV_GATT)) {
bt_mesh_proxy_prov_disable(true);
}
return 0;
}
static int bt_mesh_gap_event(struct ble_gap_event *event, void *arg)
{
@@ -253,9 +261,9 @@ int bt_mesh_suspend(void)
return err;
}
bt_mesh_hb_pub_disable();
bt_mesh_hb_suspend();
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) {
if (bt_mesh_beacon_enabled()) {
bt_mesh_beacon_disable();
}
@@ -268,7 +276,7 @@ static void model_resume(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
bool vnd, bool primary, void *user_data)
{
if (mod->pub && mod->pub->update) {
s32_t period_ms = bt_mesh_model_pub_period_get(mod);
int32_t period_ms = bt_mesh_model_pub_period_get(mod);
if (period_ms) {
k_delayed_work_submit(&mod->pub->timer, period_ms);
@@ -295,7 +303,9 @@ int bt_mesh_resume(void)
return err;
}
if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED) {
bt_mesh_hb_resume();
if (bt_mesh_beacon_enabled()) {
bt_mesh_beacon_enable();
}
@@ -319,6 +329,10 @@ int bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov,
return err;
}
#if (MYNEWT_VAL(BLE_MESH_PROXY))
bt_mesh_proxy_init();
#endif
#if (MYNEWT_VAL(BLE_MESH_PROV))
err = bt_mesh_prov_init(prov);
if (err) {
@@ -326,39 +340,66 @@ int bt_mesh_init(uint8_t own_addr_type, const struct bt_mesh_prov *prov,
}
#endif
#if (MYNEWT_VAL(BLE_MESH_PROXY))
bt_mesh_proxy_init();
#endif
#if (MYNEWT_VAL(BLE_MESH_PROV))
/* Need this to proper link.rx.buf allocation */
bt_mesh_prov_reset_link();
#endif
bt_mesh_cfg_init();
bt_mesh_net_init();
bt_mesh_trans_init();
bt_mesh_hb_init();
bt_mesh_beacon_init();
bt_mesh_adv_init();
#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_event_listener_register(&mesh_event_listener,
bt_mesh_gap_event, NULL);
#if (MYNEWT_VAL(BLE_MESH_SETTINGS))
bt_mesh_settings_init();
#endif
ble_gap_event_listener_register(&mesh_event_listener,
bt_mesh_gap_event, NULL);
return 0;
}
static void model_start(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
bool vnd, bool primary, void *user_data)
{
if (mod->cb && mod->cb->start) {
mod->cb->start(mod);
}
}
int bt_mesh_start(void)
{
if (bt_mesh_beacon_enabled()) {
bt_mesh_beacon_enable();
} else {
bt_mesh_beacon_disable();
}
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED) {
bt_mesh_proxy_gatt_enable();
bt_mesh_adv_update();
}
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
bt_mesh_lpn_init();
} else {
bt_mesh_scan_enable();
}
if (IS_ENABLED(CONFIG_BT_MESH_FRIEND)) {
bt_mesh_friend_init();
}
if (IS_ENABLED(CONFIG_BT_MESH_PROV)) {
struct bt_mesh_subnet *sub = bt_mesh_subnet_next(NULL);
uint16_t addr = bt_mesh_primary_addr();
bt_mesh_prov_complete(sub->net_idx, addr);
}
bt_mesh_hb_start();
bt_mesh_model_foreach(model_start, NULL);
return 0;
}
#endif

View File

@@ -8,14 +8,28 @@
#ifndef __MESH_PRIV_H
#define __MESH_PRIV_H
#include <stdbool.h>
#include <stdint.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)
#define BT_MESH_ADDR_IS_RFU(addr) ((addr) >= 0xff00 && (addr) <= 0xfffb)
enum bt_mesh_key_evt {
BT_MESH_KEY_ADDED, /* New key added */
BT_MESH_KEY_DELETED, /* Existing key deleted */
BT_MESH_KEY_UPDATED, /* KR phase 1, second key added */
BT_MESH_KEY_SWAPPED, /* KR phase 2, now sending on second key */
BT_MESH_KEY_REVOKED, /* KR phase 3, old key removed */
};
/** Appkey callback. Instantiate with @ref BT_MESH_APP_KEY_CB */
struct bt_mesh_app_key_cb {
void (*evt_handler)(uint16_t app_idx, uint16_t net_idx,
enum bt_mesh_key_evt evt);
};
struct bt_mesh_net;
int bt_mesh_start(void);
#define OP_GEN_ONOFF_GET BT_MESH_MODEL_OP_2(0x82, 0x01)
#define OP_GEN_ONOFF_SET BT_MESH_MODEL_OP_2(0x82, 0x02)

View File

@@ -13,19 +13,19 @@
#include "../include/mesh/model_cli.h"
#include "mesh_priv.h"
static s32_t msg_timeout = K_SECONDS(5);
static int32_t msg_timeout = K_SECONDS(5);
static struct bt_mesh_gen_model_cli *gen_onoff_cli;
static struct bt_mesh_gen_model_cli *gen_level_cli;
static u8_t transaction_id = 0;
static uint8_t transaction_id = 0;
struct gen_onoff_param {
u8_t *state;
uint8_t *state;
};
struct gen_level_param {
s16_t *level;
int16_t *level;
};
static void gen_onoff_status(struct bt_mesh_model *model,
@@ -34,7 +34,7 @@ static void gen_onoff_status(struct bt_mesh_model *model,
{
struct bt_mesh_gen_model_cli *cli = model->user_data;
struct gen_onoff_param *param;
u8_t state;
uint8_t state;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
@@ -64,7 +64,7 @@ static void gen_level_status(struct bt_mesh_model *model,
{
struct bt_mesh_gen_model_cli *cli = model->user_data;
struct gen_level_param *param;
s16_t level;
int16_t level;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
@@ -140,7 +140,7 @@ const struct bt_mesh_model_cb bt_mesh_gen_level_cli_cb = {
.init = level_cli_init,
};
static int cli_wait(struct bt_mesh_gen_model_cli *cli, void *param, u32_t op)
static int cli_wait(struct bt_mesh_gen_model_cli *cli, void *param, uint32_t op)
{
int err;
@@ -157,8 +157,8 @@ static int cli_wait(struct bt_mesh_gen_model_cli *cli, void *param, u32_t op)
return err;
}
int bt_mesh_gen_onoff_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *state)
int bt_mesh_gen_onoff_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
uint8_t *state)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct bt_mesh_msg_ctx ctx = {
@@ -186,8 +186,8 @@ done:
return err;
}
int bt_mesh_gen_onoff_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t val, u8_t *state)
int bt_mesh_gen_onoff_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
uint8_t val, uint8_t *state)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
struct bt_mesh_msg_ctx ctx = {
@@ -229,8 +229,8 @@ done:
return err;
}
int bt_mesh_gen_level_get(u16_t net_idx, u16_t addr, u16_t app_idx,
s16_t *level)
int bt_mesh_gen_level_get(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
int16_t *level)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct bt_mesh_msg_ctx ctx = {
@@ -258,8 +258,8 @@ done:
return err;
}
int bt_mesh_gen_level_set(u16_t net_idx, u16_t addr, u16_t app_idx,
s16_t val, s16_t *state)
int bt_mesh_gen_level_set(uint16_t net_idx, uint16_t addr, uint16_t app_idx,
int16_t val, int16_t *state)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4);
struct bt_mesh_msg_ctx ctx = {

View File

@@ -22,7 +22,7 @@ static void gen_onoff_status(struct bt_mesh_model *model,
{
struct bt_mesh_gen_onoff_srv *cb = model->user_data;
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
u8_t *state;
uint8_t *state;
bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_STATUS);
state = net_buf_simple_add(msg, 1);
@@ -53,7 +53,7 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct bt_mesh_gen_onoff_srv *cb = model->user_data;
u8_t state;
uint8_t state;
state = buf->om_data[0];
@@ -79,7 +79,7 @@ static void gen_level_status(struct bt_mesh_model *model,
{
struct bt_mesh_gen_level_srv *cb = model->user_data;
struct os_mbuf *msg = NET_BUF_SIMPLE(4);
s16_t *level;
int16_t *level;
bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_STATUS);
level = net_buf_simple_add(msg, 2);
@@ -109,9 +109,9 @@ static void gen_level_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf) {
struct bt_mesh_gen_level_srv *cb = model->user_data;
s16_t level;
int16_t level;
level = (s16_t) net_buf_simple_pull_le16(buf);
level = (int16_t) net_buf_simple_pull_le16(buf);
BT_DBG("level: %d", level);
if (cb && cb->set) {
@@ -132,7 +132,7 @@ static void light_lightness_status(struct bt_mesh_model *model,
{
struct bt_mesh_light_lightness_srv *cb = model->user_data;
struct os_mbuf *msg = NET_BUF_SIMPLE(4);
s16_t *lightness;
int16_t *lightness;
bt_mesh_model_msg_init(msg, OP_LIGHT_LIGHTNESS_STATUS);
lightness = net_buf_simple_add(msg, 2);
@@ -162,9 +162,9 @@ static void light_lightness_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf) {
struct bt_mesh_light_lightness_srv *cb = model->user_data;
s16_t lightness;
int16_t lightness;
lightness = (s16_t) net_buf_simple_pull_le16(buf);
lightness = (int16_t) net_buf_simple_pull_le16(buf);
BT_DBG("lightness: %d", lightness);
if (cb && cb->set) {

File diff suppressed because it is too large Load Diff

View File

@@ -9,13 +9,7 @@
#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
#include "subnet.h"
#define BT_MESH_IV_UPDATE(flags) ((flags >> 1) & 0x01)
#define BT_MESH_KEY_REFRESH(flags) (flags & 0x01)
@@ -31,64 +25,13 @@
CONFIG_BT_MESH_IVU_DIVIDER)
#define BT_MESH_IVU_TIMEOUT K_HOURS(BT_MESH_IVU_HOURS)
struct bt_mesh_app_key {
u16_t net_idx;
u16_t app_idx;
bool updated;
struct bt_mesh_app_keys {
u8_t id;
u8_t val[16];
} keys[2];
};
struct bt_mesh_net_cred;
struct bt_mesh_node {
u16_t addr;
u16_t net_idx;
u8_t dev_key[16];
u8_t num_elem;
};
struct bt_mesh_subnet {
u32_t beacon_sent; /* Timestamp of last sent beacon */
u8_t beacons_last; /* Number of beacons during last
* observation window
*/
u8_t beacons_cur; /* Number of beaconds observed during
* currently ongoing window.
*/
u8_t beacon_cache[21]; /* Cached last authenticated beacon */
u16_t net_idx; /* NetKeyIndex */
bool kr_flag; /* Key Refresh Flag */
u8_t kr_phase; /* Key Refresh Phase */
u8_t node_id; /* Node Identity State */
u32_t node_id_start; /* Node Identity started timestamp */
u8_t auth[8]; /* Beacon Authentication Value */
struct bt_mesh_subnet_keys {
u8_t net[16]; /* NetKey */
u8_t nid; /* NID */
u8_t enc[16]; /* EncKey */
u8_t net_id[8]; /* Network ID */
#if (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;
#if (MYNEWT_VAL(BLE_MESH_SETTINGS))
bool store;
#endif
u32_t seq;
uint16_t addr;
uint16_t net_idx;
uint8_t dev_key[16];
uint8_t num_elem;
};
#if MYNEWT_VAL(BLE_MESH_FRIEND)
@@ -100,23 +43,23 @@ struct bt_mesh_rpl {
#endif
struct bt_mesh_friend {
u16_t lpn;
u8_t recv_delay;
u8_t fsn:1,
uint16_t lpn;
uint8_t recv_delay;
uint8_t fsn:1,
send_last:1,
pending_req:1,
sec_update:1,
pending_buf:1,
valid:1,
established:1;
s32_t poll_to;
u8_t num_elem;
u16_t lpn_counter;
u16_t counter;
int32_t poll_to;
uint8_t num_elem;
uint16_t lpn_counter;
uint16_t counter;
u16_t net_idx;
struct bt_mesh_subnet *subnet;
u16_t sub_list[FRIEND_SUB_LIST_SIZE];
struct bt_mesh_net_cred cred[2];
uint16_t sub_list[FRIEND_SUB_LIST_SIZE];
struct k_delayed_work timer;
@@ -127,19 +70,19 @@ struct bt_mesh_friend {
* the current number of segments, in the queue. This is
* used for Friend Queue free space calculations.
*/
u8_t seg_count;
uint8_t seg_count;
} seg[FRIEND_SEG_RX];
struct os_mbuf *last;
struct net_buf_slist_t queue;
u32_t queue_size;
uint32_t queue_size;
/* Friend Clear Procedure */
struct {
u32_t start; /* Clear Procedure start */
u16_t frnd; /* Previous Friend's address */
u16_t repeat_sec; /* Repeat timeout in seconds */
uint32_t start; /* Clear Procedure start */
uint16_t frnd; /* Previous Friend's address */
uint16_t repeat_sec; /* Repeat timeout in seconds */
struct k_delayed_work timer; /* Repeat timer */
} clear;
};
@@ -165,23 +108,23 @@ struct bt_mesh_lpn {
} state;
/* Transaction Number (used for subscription list) */
u8_t xact_next;
u8_t xact_pending;
u8_t sent_req;
uint8_t xact_next;
uint8_t xact_pending;
uint8_t sent_req;
/* Address of our Friend when we're a LPN. Unassigned if we don't
* have a friend yet.
*/
u16_t frnd;
uint16_t frnd;
/* Value from the friend offer */
u8_t recv_win;
uint8_t recv_win;
u8_t req_attempts; /* Number of Request attempts */
uint8_t req_attempts; /* Number of Request attempts */
s32_t poll_timeout;
int32_t poll_timeout;
u8_t groups_changed:1, /* Friend Subscription List needs updating */
uint8_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 */
@@ -189,22 +132,29 @@ struct bt_mesh_lpn {
clear_success:1; /* Friend Clear Confirm received */
/* Friend Queue Size */
u8_t queue_size;
uint8_t queue_size;
/* FriendCounter */
uint16_t frnd_counter;
/* LPNCounter */
u16_t counter;
uint16_t lpn_counter;
/* Previous Friend of this LPN */
u16_t old_friend;
uint16_t old_friend;
/* Duration reported for last advertising packet */
u16_t adv_duration;
uint16_t adv_duration;
/* Next LPN related action timer */
struct k_delayed_work timer;
/* Subscribed groups */
u16_t groups[LPN_GROUPS];
uint16_t groups[LPN_GROUPS];
struct bt_mesh_subnet *sub;
struct bt_mesh_net_cred cred[2];
/* Bit fields for tracking which groups the Friend knows about */
ATOMIC_DEFINE(added, LPN_GROUPS);
@@ -231,15 +181,20 @@ enum {
BT_MESH_CFG_PENDING,
BT_MESH_MOD_PENDING,
BT_MESH_VA_PENDING,
BT_MESH_NODES_PENDING,
/* Feature flags */
BT_MESH_RELAY,
BT_MESH_BEACON,
BT_MESH_GATT_PROXY,
BT_MESH_FRIEND,
/* Don't touch - intentionally last */
BT_MESH_FLAG_COUNT,
};
struct bt_mesh_net {
u32_t iv_index; /* Current IV Index */
u32_t seq; /* Next outgoing sequence number (24 bits) */
uint32_t iv_index; /* Current IV Index */
uint32_t seq; /* Next outgoing sequence number (24 bits) */
ATOMIC_DEFINE(flags, BT_MESH_FLAG_COUNT);
@@ -257,22 +212,16 @@ struct bt_mesh_net {
#endif
/* Number of hours in current IV Update state */
u8_t ivu_duration;
uint8_t ivu_duration;
uint8_t net_xmit;
uint8_t relay_xmit;
uint8_t default_ttl;
/* Timer to track duration in current IV Update state */
struct k_delayed_work ivu_timer;
u8_t dev_key[16];
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
struct bt_mesh_node nodes[MYNEWT_VAL(BLE_MESH_NODE_COUNT)];
#endif
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)];
uint8_t dev_key[16];
};
/* Network interface */
@@ -287,24 +236,24 @@ enum bt_mesh_net_if {
struct bt_mesh_net_rx {
struct bt_mesh_subnet *sub;
struct bt_mesh_msg_ctx ctx;
u32_t seq; /* Sequence Number */
u8_t old_iv:1, /* iv_index - 1 was used */
uint32_t seq; /* Sequence Number */
uint8_t old_iv:1, /* iv_index - 1 was used */
new_key:1, /* Data was encrypted with updated key */
friend_cred:1, /* Data was encrypted with friend cred */
ctl:1, /* Network Control */
net_if:2, /* Network interface */
local_match:1, /* Matched a local element */
friend_match:1; /* Matched an LPN we're friends for */
u16_t msg_cache_idx; /* Index of entry in message cache */
uint16_t msg_cache_idx; /* Index of entry in message cache */
};
/* Encoding context for Network/Transport data */
struct bt_mesh_net_tx {
struct bt_mesh_subnet *sub;
struct bt_mesh_msg_ctx *ctx;
u16_t src;
u8_t xmit;
u8_t friend_cred:1,
uint16_t src;
uint8_t xmit;
uint8_t friend_cred:1,
aszmic:1,
aid:6;
};
@@ -318,80 +267,36 @@ extern struct bt_mesh_net bt_mesh;
#define BT_MESH_NET_HDR_LEN 9
int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys,
const u8_t key[16]);
static inline void *net_buf_user_data(const struct os_mbuf *buf)
{
return (void *)buf->om_data;
}
int bt_mesh_net_create(u16_t idx, u8_t flags, const u8_t key[16],
u32_t iv_index);
int bt_mesh_net_create(uint16_t idx, uint8_t flags, const uint8_t key[16],
uint32_t iv_index);
u8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub);
bool bt_mesh_kr_update(struct bt_mesh_subnet *sub, u8_t new_kr, bool new_key);
void bt_mesh_net_revoke_keys(struct bt_mesh_subnet *sub);
int bt_mesh_net_beacon_update(struct bt_mesh_subnet *sub);
void bt_mesh_rpl_reset(void);
bool bt_mesh_net_iv_update(u32_t iv_index, bool iv_update);
void bt_mesh_net_sec_update(struct bt_mesh_subnet *sub);
struct bt_mesh_subnet *bt_mesh_subnet_get(u16_t net_idx);
struct bt_mesh_subnet *bt_mesh_subnet_find(const u8_t net_id[8], u8_t flags,
u32_t iv_index, const u8_t auth[8],
bool *new_key);
bool bt_mesh_net_iv_update(uint32_t iv_index, bool iv_update);
int bt_mesh_net_encode(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
bool proxy);
int bt_mesh_net_decode(struct os_mbuf *in, enum bt_mesh_net_if net_if,
struct bt_mesh_net_rx *rx, struct os_mbuf *out);
int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
const struct bt_mesh_send_cb *cb, void *cb_data);
int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct os_mbuf *buf,
bool new_key, const struct bt_mesh_send_cb *cb,
void *cb_data);
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);
void bt_mesh_net_recv(struct os_mbuf *data, s8_t rssi,
void bt_mesh_net_recv(struct os_mbuf *data, int8_t rssi,
enum bt_mesh_net_if net_if);
u32_t bt_mesh_next_seq(void);
void bt_mesh_net_loopback_clear(uint16_t net_idx);
void bt_mesh_net_start(void);
uint32_t bt_mesh_next_seq(void);
void bt_mesh_net_init(void);
void bt_mesh_net_header_parse(struct os_mbuf *buf,
struct bt_mesh_net_rx *rx);
/* Friendship Credential Management */
struct friend_cred {
u16_t net_idx;
u16_t addr;
u16_t lpn_counter;
u16_t frnd_counter;
struct {
u8_t nid; /* NID */
u8_t enc[16]; /* EncKey */
u8_t privacy[16]; /* PrivacyKey */
} cred[2];
};
int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv);
int friend_cred_set(struct friend_cred *cred, u8_t idx, const u8_t net_key[16]);
void friend_cred_refresh(u16_t net_idx);
int friend_cred_update(struct bt_mesh_subnet *sub);
struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr,
u16_t lpn_counter, u16_t frnd_counter);
void friend_cred_clear(struct friend_cred *cred);
int friend_cred_del(u16_t net_idx, u16_t addr);
static inline void send_cb_finalize(const struct bt_mesh_send_cb *cb,
void *cb_data)

View File

@@ -161,4 +161,4 @@ void bt_mesh_node_del(struct bt_mesh_node *node, bool store)
}
#endif
#endif
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,891 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_PROV_LOG
#if MYNEWT_VAL(BLE_MESH)
#include <stdint.h>
#include <string.h>
#include "../include/mesh/mesh.h"
#include <nimble/porting/nimble/include/os/os_mbuf.h>
#include "net.h"
#include "prov.h"
#include "adv.h"
#include "crypto.h"
#include "beacon.h"
#include "prov.h"
#include "../include/mesh/glue.h"
#define GPCF(gpc) (gpc & 0x03)
#define GPC_START(last_seg) (((last_seg) << 2) | 0x00)
#define GPC_ACK 0x01
#define GPC_CONT(seg_id) (((seg_id) << 2) | 0x02)
#define GPC_CTL(op) (((op) << 2) | 0x03)
#define START_PAYLOAD_MAX 20
#define CONT_PAYLOAD_MAX 23
#define START_LAST_SEG(gpc) (gpc >> 2)
#define CONT_SEG_INDEX(gpc) (gpc >> 2)
#define BEARER_CTL(gpc) (gpc >> 2)
#define LINK_OPEN 0x00
#define LINK_ACK 0x01
#define LINK_CLOSE 0x02
#define XACT_SEG_DATA(_seg) (&link.rx.buf->om_data[20 + ((_seg - 1) * 23)])
#define XACT_SEG_RECV(_seg) (link.rx.seg &= ~(1 << (_seg)))
#define XACT_ID_MAX 0x7f
#define XACT_ID_NVAL 0xff
#define SEG_NVAL 0xff
#define RETRANSMIT_TIMEOUT K_MSEC(MYNEWT_VAL(BLE_MESH_PB_ADV_RETRANS_TIMEOUT))
#define BUF_TIMEOUT K_MSEC(400)
#define CLOSING_TIMEOUT K_SECONDS(3)
#define TRANSACTION_TIMEOUT K_SECONDS(30)
/* Acked messages, will do retransmissions manually, taking acks into account:
*/
#define RETRANSMITS_RELIABLE 0
/* Unacked messages: */
#define RETRANSMITS_UNRELIABLE 2
/* PDU acks: */
#define RETRANSMITS_ACK 2
enum {
ADV_LINK_ACTIVE, /* Link has been opened */
ADV_LINK_ACK_RECVD, /* Ack for link has been received */
ADV_LINK_CLOSING, /* Link is closing down */
ADV_LINK_INVALID, /* Error occurred during provisioning */
ADV_ACK_PENDING, /* An acknowledgment is being sent */
ADV_PROVISIONER, /* The link was opened as provisioner */
ADV_NUM_FLAGS,
};
struct pb_adv {
uint32_t id; /* Link ID */
ATOMIC_DEFINE(flags, ADV_NUM_FLAGS);
const struct prov_bearer_cb *cb;
void *cb_data;
struct {
uint8_t id; /* Most recent transaction ID */
uint8_t seg; /* Bit-field of unreceived segments */
uint8_t last_seg; /* Last segment (to check length) */
uint8_t fcs; /* Expected FCS value */
struct os_mbuf *buf;
} rx;
struct {
/* Start timestamp of the transaction */
int64_t start;
/* Transaction id */
uint8_t id;
/* Current ack id */
uint8_t pending_ack;
/* Pending outgoing buffer(s) */
struct os_mbuf *buf[3];
prov_bearer_send_complete_t cb;
void *cb_data;
/* Retransmit timer */
struct k_delayed_work retransmit;
} tx;
/* Protocol timeout */
struct k_delayed_work prot_timer;
};
struct prov_rx {
uint32_t link_id;
uint8_t xact_id;
uint8_t gpc;
};
static struct os_mbuf *rx_buf;
static struct pb_adv link;
static void gen_prov_ack_send(uint8_t xact_id);
static void link_open(struct prov_rx *rx, struct os_mbuf *buf);
static void link_ack(struct prov_rx *rx, struct os_mbuf *buf);
static void link_close(struct prov_rx *rx, struct os_mbuf *buf);
static void buf_sent(int err, void *user_data)
{
BT_DBG("buf_send");
if (!link.tx.buf[0]) {
return;
}
BT_DBG("submit retransmit");
k_delayed_work_submit(&link.tx.retransmit, RETRANSMIT_TIMEOUT);
}
static struct bt_mesh_send_cb buf_sent_cb = {
.end = buf_sent,
};
static uint8_t last_seg(uint8_t len)
{
if (len <= START_PAYLOAD_MAX) {
return 0;
}
len -= START_PAYLOAD_MAX;
return 1 + (len / CONT_PAYLOAD_MAX);
}
static void free_segments(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) {
struct os_mbuf *buf = link.tx.buf[i];
if (!buf) {
break;
}
link.tx.buf[i] = NULL;
/* Mark as canceled */
BT_MESH_ADV(buf)->busy = 0U;
net_buf_unref(buf);
}
}
static uint8_t next_transaction_id(uint8_t id)
{
return (((id + 1) & XACT_ID_MAX) | (id & (XACT_ID_MAX+1)));
}
static void prov_clear_tx(void)
{
BT_DBG("");
k_delayed_work_cancel(&link.tx.retransmit);
free_segments();
}
static void reset_adv_link(void)
{
BT_DBG("");
prov_clear_tx();
k_delayed_work_cancel(&link.prot_timer);
if (atomic_test_bit(link.flags, ADV_PROVISIONER)) {
/* Clear everything except the retransmit and protocol timer
* delayed work objects.
*/
(void)memset(&link, 0, offsetof(struct pb_adv, tx.retransmit));
link.rx.id = XACT_ID_NVAL;
} else {
/* Accept another provisioning attempt */
link.id = 0;
atomic_clear(link.flags);
link.rx.id = XACT_ID_MAX;
link.tx.id = XACT_ID_NVAL;
}
link.tx.pending_ack = XACT_ID_NVAL;
if (!rx_buf) {
rx_buf = NET_BUF_SIMPLE(65);
}
link.rx.buf = rx_buf;
net_buf_simple_reset(link.rx.buf);
}
static void close_link(enum prov_bearer_link_status reason)
{
const struct prov_bearer_cb *cb = link.cb;
void *cb_data = link.cb_data;
reset_adv_link();
cb->link_closed(&pb_adv, cb_data, reason);
}
static struct os_mbuf *adv_buf_create(uint8_t retransmits)
{
struct os_mbuf *buf;
buf = bt_mesh_adv_create(BT_MESH_ADV_PROV,
BT_MESH_TRANSMIT(retransmits, 20),
BUF_TIMEOUT);
if (!buf) {
BT_ERR("Out of provisioning buffers");
return NULL;
}
return buf;
}
static void ack_complete(uint16_t duration, int err, void *user_data)
{
BT_DBG("xact 0x%x complete", (uint8_t)link.tx.pending_ack);
atomic_clear_bit(link.flags, ADV_ACK_PENDING);
}
static bool ack_pending(void)
{
return atomic_test_bit(link.flags, ADV_ACK_PENDING);
}
static void prov_failed(uint8_t err)
{
BT_DBG("%u", err);
link.cb->error(&pb_adv, link.cb_data, err);
atomic_set_bit(link.flags, ADV_LINK_INVALID);
}
static void prov_msg_recv(void)
{
k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT);
if (!bt_mesh_fcs_check(link.rx.buf, link.rx.fcs)) {
BT_ERR("Incorrect FCS");
return;
}
gen_prov_ack_send(link.rx.id);
if (atomic_test_bit(link.flags, ADV_LINK_INVALID)) {
BT_WARN("Unexpected msg 0x%02x on invalidated link",
link.rx.buf->om_data[0]);
prov_failed(PROV_ERR_UNEXP_PDU);
return;
}
link.cb->recv(&pb_adv, link.cb_data, link.rx.buf);
}
static void protocol_timeout(struct ble_npl_event *work)
{
BT_DBG("");
link.rx.seg = 0U;
close_link(PROV_BEARER_LINK_STATUS_TIMEOUT);
}
/*******************************************************************************
* Generic provisioning
******************************************************************************/
static void gen_prov_ack_send(uint8_t xact_id)
{
static const struct bt_mesh_send_cb cb = {
.start = ack_complete,
};
const struct bt_mesh_send_cb *complete;
struct os_mbuf *buf;
bool pending = atomic_test_and_set_bit(link.flags, ADV_ACK_PENDING);
BT_DBG("xact_id 0x%x", xact_id);
if (pending && link.tx.pending_ack == xact_id) {
BT_DBG("Not sending duplicate ack");
return;
}
buf = adv_buf_create(RETRANSMITS_ACK);
if (!buf) {
atomic_clear_bit(link.flags, ADV_ACK_PENDING);
return;
}
if (pending) {
complete = NULL;
} else {
link.tx.pending_ack = xact_id;
complete = &cb;
}
net_buf_add_be32(buf, link.id);
net_buf_add_u8(buf, xact_id);
net_buf_add_u8(buf, GPC_ACK);
bt_mesh_adv_send(buf, complete, NULL);
net_buf_unref(buf);
}
static void gen_prov_cont(struct prov_rx *rx, struct os_mbuf *buf)
{
uint8_t seg = CONT_SEG_INDEX(rx->gpc);
BT_DBG("len %u, seg_index %u", buf->om_len, seg);
if (!link.rx.seg && link.rx.id == rx->xact_id) {
if (!ack_pending()) {
BT_DBG("Resending ack");
gen_prov_ack_send(rx->xact_id);
}
return;
}
if (!link.rx.seg &&
next_transaction_id(link.rx.id) == rx->xact_id) {
BT_DBG("Start segment lost");
link.rx.id = rx->xact_id;
net_buf_simple_reset(link.rx.buf);
link.rx.seg = SEG_NVAL;
link.rx.last_seg = SEG_NVAL;
prov_clear_tx();
} else if (rx->xact_id != link.rx.id) {
BT_WARN("Data for unknown transaction (0x%x != 0x%x)",
rx->xact_id, link.rx.id);
return;
}
if (seg > link.rx.last_seg) {
BT_ERR("Invalid segment index %u", seg);
prov_failed(PROV_ERR_NVAL_FMT);
return;
}
if (!(link.rx.seg & BIT(seg))) {
BT_DBG("Ignoring already received segment");
return;
}
memcpy(XACT_SEG_DATA(seg), buf->om_data, buf->om_len);
XACT_SEG_RECV(seg);
if (seg == link.rx.last_seg && !(link.rx.seg & BIT(0))) {
uint8_t expect_len;
expect_len = (link.rx.buf->om_len - 20U -
((link.rx.last_seg - 1) * 23U));
if (expect_len != buf->om_len) {
BT_ERR("Incorrect last seg len: %u != %u", expect_len,
buf->om_len);
prov_failed(PROV_ERR_NVAL_FMT);
return;
}
}
if (!link.rx.seg) {
prov_msg_recv();
}
}
static void gen_prov_ack(struct prov_rx *rx, struct os_mbuf *buf)
{
BT_DBG("len %u", buf->om_len);
if (!link.tx.buf[0]) {
return;
}
if (rx->xact_id == link.tx.id) {
/* Don't clear resending of link_close messages */
if (!atomic_test_bit(link.flags, ADV_LINK_CLOSING)) {
prov_clear_tx();
}
if (link.tx.cb) {
link.tx.cb(0, link.tx.cb_data);
}
}
}
static void gen_prov_start(struct prov_rx *rx, struct os_mbuf *buf)
{
uint8_t seg = SEG_NVAL;
if (rx->xact_id == link.rx.id) {
if (!link.rx.seg) {
if (!ack_pending()) {
BT_DBG("Resending ack");
gen_prov_ack_send(rx->xact_id);
}
return;
}
if (!(link.rx.seg & BIT(0))) {
BT_DBG("Ignoring duplicate segment");
return;
}
} else if (rx->xact_id != next_transaction_id(link.rx.id)) {
BT_WARN("Unexpected xact 0x%x, expected 0x%x", rx->xact_id,
next_transaction_id(link.rx.id));
return;
}
net_buf_simple_reset(link.rx.buf);
link.rx.buf->om_len = net_buf_simple_pull_be16(buf);
link.rx.id = rx->xact_id;
link.rx.fcs = net_buf_simple_pull_u8(buf);
BT_DBG("%p len %u last_seg %u total_len %u fcs 0x%02x", link.rx.buf, buf->om_len,
START_LAST_SEG(rx->gpc), link.rx.buf->om_len, link.rx.fcs);
if (link.rx.buf->om_len < 1) {
BT_ERR("Ignoring zero-length provisioning PDU");
prov_failed(PROV_ERR_NVAL_FMT);
return;
}
if (START_LAST_SEG(rx->gpc) > 0 && link.rx.buf->om_len <= 20U) {
BT_ERR("Too small total length for multi-segment PDU");
prov_failed(PROV_ERR_NVAL_FMT);
return;
}
prov_clear_tx();
link.rx.last_seg = START_LAST_SEG(rx->gpc);
if ((link.rx.seg & BIT(0)) &&
(find_msb_set((~link.rx.seg) & SEG_NVAL) - 1 > link.rx.last_seg)) {
BT_ERR("Invalid segment index %u", seg);
prov_failed(PROV_ERR_NVAL_FMT);
return;
}
if (link.rx.seg) {
seg = link.rx.seg;
}
link.rx.seg = seg & ((1 << (START_LAST_SEG(rx->gpc) + 1)) - 1);
memcpy(link.rx.buf->om_data, buf->om_data, buf->om_len);
XACT_SEG_RECV(0);
if (!link.rx.seg) {
prov_msg_recv();
}
}
static void gen_prov_ctl(struct prov_rx *rx, struct os_mbuf *buf)
{
BT_DBG("op 0x%02x len %u", BEARER_CTL(rx->gpc), buf->om_len);
switch (BEARER_CTL(rx->gpc)) {
case LINK_OPEN:
link_open(rx, buf);
break;
case LINK_ACK:
if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) {
return;
}
link_ack(rx, buf);
break;
case LINK_CLOSE:
if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) {
return;
}
link_close(rx, buf);
break;
default:
BT_ERR("Unknown bearer opcode: 0x%02x", BEARER_CTL(rx->gpc));
if (IS_ENABLED(CONFIG_BT_TESTING)) {
bt_test_mesh_prov_invalid_bearer(BEARER_CTL(rx->gpc));
}
return;
}
}
static const struct {
void (*func)(struct prov_rx *rx, struct os_mbuf *buf);
bool require_link;
uint8_t min_len;
} gen_prov[] = {
{ gen_prov_start, true, 3 },
{ gen_prov_ack, true, 0 },
{ gen_prov_cont, true, 0 },
{ gen_prov_ctl, false, 0 },
};
static void gen_prov_recv(struct prov_rx *rx, struct os_mbuf *buf)
{
if (buf->om_len < gen_prov[GPCF(rx->gpc)].min_len) {
BT_ERR("Too short GPC message type %u", GPCF(rx->gpc));
return;
}
if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE) &&
gen_prov[GPCF(rx->gpc)].require_link) {
BT_DBG("Ignoring message that requires active link");
return;
}
gen_prov[GPCF(rx->gpc)].func(rx, buf);
}
/*******************************************************************************
* TX
******************************************************************************/
static void send_reliable(void)
{
int i;
link.tx.start = k_uptime_get();
for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) {
struct os_mbuf *buf = link.tx.buf[i];
if (!buf) {
break;
}
if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) {
bt_mesh_adv_send(buf, NULL, NULL);
} else {
bt_mesh_adv_send(buf, &buf_sent_cb, NULL);
}
}
}
static void prov_retransmit(struct ble_npl_event *work)
{
int32_t timeout_ms;
int i;
BT_DBG("");
if (!atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) {
BT_WARN("Link not active");
return;
}
/*
* According to mesh profile spec (5.3.1.4.3), the close message should
* be restransmitted at least three times. Retransmit the link_close
* message until CLOSING_TIMEOUT has elapsed.
*/
if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) {
timeout_ms = CLOSING_TIMEOUT;
} else {
timeout_ms = TRANSACTION_TIMEOUT;
}
if (k_uptime_get() - link.tx.start > timeout_ms) {
if (atomic_test_bit(link.flags, ADV_LINK_CLOSING)) {
close_link(PROV_BEARER_LINK_STATUS_SUCCESS);
} else {
BT_WARN("Giving up transaction");
close_link(PROV_BEARER_LINK_STATUS_TIMEOUT);
}
return;
}
for (i = 0; i < ARRAY_SIZE(link.tx.buf); i++) {
struct os_mbuf *buf = link.tx.buf[i];
if (!buf) {
break;
}
if (BT_MESH_ADV(buf)->busy) {
continue;
}
BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
if (i + 1 < ARRAY_SIZE(link.tx.buf) && link.tx.buf[i + 1]) {
bt_mesh_adv_send(buf, NULL, NULL);
} else {
bt_mesh_adv_send(buf, &buf_sent_cb, NULL);
}
}
}
static int bearer_ctl_send(uint8_t op, const void *data, uint8_t data_len,
bool reliable)
{
struct os_mbuf *buf;
BT_DBG("op 0x%02x data_len %u", op, data_len);
prov_clear_tx();
k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT);
buf = adv_buf_create(reliable ? RETRANSMITS_RELIABLE :
RETRANSMITS_UNRELIABLE);
if (!buf) {
return -ENOBUFS;
}
net_buf_add_be32(buf, link.id);
/* Transaction ID, always 0 for Bearer messages */
net_buf_add_u8(buf, 0x00);
net_buf_add_u8(buf, GPC_CTL(op));
net_buf_add_mem(buf, data, data_len);
if (reliable) {
link.tx.buf[0] = buf;
send_reliable();
} else {
bt_mesh_adv_send(buf, &buf_sent_cb, NULL);
net_buf_unref(buf);
}
return 0;
}
static int prov_send_adv(struct os_mbuf *msg,
prov_bearer_send_complete_t cb, void *cb_data)
{
struct os_mbuf *start, *buf;
uint8_t seg_len, seg_id;
prov_clear_tx();
k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT);
start = adv_buf_create(RETRANSMITS_RELIABLE);
if (!start) {
return -ENOBUFS;
}
link.tx.id = next_transaction_id(link.tx.id);
net_buf_add_be32(start, link.id);
net_buf_add_u8(start, link.tx.id);
net_buf_add_u8(start, GPC_START(last_seg(msg->om_len)));
net_buf_add_be16(start, msg->om_len);
net_buf_add_u8(start, bt_mesh_fcs_calc(msg->om_data, msg->om_len));
link.tx.buf[0] = start;
link.tx.cb = cb;
link.tx.cb_data = cb_data;
BT_DBG("xact_id: 0x%x len: %u", link.tx.id, msg->om_len);
seg_len = MIN(msg->om_len, START_PAYLOAD_MAX);
BT_DBG("seg 0 len %u: %s", seg_len, bt_hex(msg->om_data, seg_len));
net_buf_add_mem(start, msg->om_data, seg_len);
net_buf_simple_pull_mem(msg, seg_len);
buf = start;
for (seg_id = 1U; msg->om_len > 0; seg_id++) {
if (seg_id >= ARRAY_SIZE(link.tx.buf)) {
BT_ERR("Too big message");
free_segments();
return -E2BIG;
}
buf = adv_buf_create(RETRANSMITS_RELIABLE);
if (!buf) {
free_segments();
return -ENOBUFS;
}
link.tx.buf[seg_id] = buf;
seg_len = MIN(msg->om_len, CONT_PAYLOAD_MAX);
BT_DBG("seg %u len %u: %s", seg_id, seg_len,
bt_hex(msg->om_data, seg_len));
net_buf_add_be32(buf, link.id);
net_buf_add_u8(buf, link.tx.id);
net_buf_add_u8(buf, GPC_CONT(seg_id));
net_buf_add_mem(buf, msg->om_data, seg_len);
net_buf_simple_pull_mem(msg, seg_len);
}
send_reliable();
return 0;
}
/*******************************************************************************
* Link management rx
******************************************************************************/
static void link_open(struct prov_rx *rx, struct os_mbuf *buf)
{
BT_DBG("len %u", buf->om_len);
if (buf->om_len < 16) {
BT_ERR("Too short bearer open message (len %u)", buf->om_len);
return;
}
if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) {
/* Send another link ack if the provisioner missed the last */
if (link.id == rx->link_id) {
BT_DBG("Resending link ack");
bearer_ctl_send(LINK_ACK, NULL, 0, false);
} else {
BT_DBG("Ignoring bearer open: link already active");
}
return;
}
if (memcmp(buf->om_data, bt_mesh_prov_get()->uuid, 16)) {
BT_DBG("Bearer open message not for us");
return;
}
link.id = rx->link_id;
atomic_set_bit(link.flags, ADV_LINK_ACTIVE);
net_buf_simple_reset(link.rx.buf);
bearer_ctl_send(LINK_ACK, NULL, 0, false);
link.cb->link_opened(&pb_adv, link.cb_data);
}
static void link_ack(struct prov_rx *rx, struct os_mbuf *buf)
{
BT_DBG("len %u", buf->om_len);
if (atomic_test_bit(link.flags, ADV_PROVISIONER)) {
if (atomic_test_and_set_bit(link.flags, ADV_LINK_ACK_RECVD)) {
return;
}
prov_clear_tx();
link.cb->link_opened(&pb_adv, link.cb_data);
}
}
static void link_close(struct prov_rx *rx, struct os_mbuf *buf)
{
BT_DBG("len %u", buf->om_len);
if (buf->om_len != 1) {
return;
}
close_link(net_buf_simple_pull_u8(buf));
}
/*******************************************************************************
* Higher level functionality
******************************************************************************/
void bt_mesh_pb_adv_recv(struct os_mbuf *buf)
{
struct prov_rx rx;
if (!link.cb) {
return;
}
if (buf->om_len < 6) {
BT_WARN("Too short provisioning packet (len %u)", buf->om_len);
return;
}
rx.link_id = net_buf_simple_pull_be32(buf);
rx.xact_id = net_buf_simple_pull_u8(buf);
rx.gpc = net_buf_simple_pull_u8(buf);
if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE) && link.id != rx.link_id) {
return;
}
BT_DBG("link_id 0x%08x xact_id 0x%x", rx.link_id, rx.xact_id);
gen_prov_recv(&rx, buf);
}
static int prov_link_open(const uint8_t uuid[16], int32_t timeout,
const struct prov_bearer_cb *cb, void *cb_data)
{
BT_DBG("uuid %s", bt_hex(uuid, 16));
if (atomic_test_and_set_bit(link.flags, ADV_LINK_ACTIVE)) {
return -EBUSY;
}
atomic_set_bit(link.flags, ADV_PROVISIONER);
bt_rand(&link.id, sizeof(link.id));
link.tx.id = XACT_ID_MAX;
link.rx.id = XACT_ID_NVAL;
link.cb = cb;
link.cb_data = cb_data;
net_buf_simple_reset(link.rx.buf);
bearer_ctl_send(LINK_OPEN, uuid, 16, true);
return 0;
}
static int prov_link_accept(const struct prov_bearer_cb *cb, void *cb_data)
{
if (atomic_test_bit(link.flags, ADV_LINK_ACTIVE)) {
return -EBUSY;
}
link.rx.id = XACT_ID_MAX;
link.tx.id = XACT_ID_NVAL;
link.cb = cb;
link.cb_data = cb_data;
/* Make sure we're scanning for provisioning inviations */
bt_mesh_scan_enable();
/* Enable unprovisioned beacon sending */
bt_mesh_beacon_enable();
return 0;
}
static void prov_link_close(enum prov_bearer_link_status status)
{
if (atomic_test_and_set_bit(link.flags, ADV_LINK_CLOSING)) {
return;
}
bearer_ctl_send(LINK_CLOSE, &status, 1, true);
}
void pb_adv_init(void)
{
k_delayed_work_init(&link.prot_timer, protocol_timeout);
k_delayed_work_init(&link.tx.retransmit, prov_retransmit);
if (!rx_buf) {
rx_buf = NET_BUF_SIMPLE(65);
}
link.rx.buf = rx_buf;
net_buf_simple_reset(link.rx.buf);
}
void pb_adv_reset(void)
{
reset_adv_link();
}
const struct prov_bearer pb_adv = {
.type = BT_MESH_PROV_ADV,
.link_open = prov_link_open,
.link_accept = prov_link_accept,
.link_close = prov_link_close,
.send = prov_send_adv,
.clear_tx = prov_clear_tx,
};
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,163 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#define MESH_LOG_MODULE BLE_MESH_PROV_LOG
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#include "../include/mesh/mesh.h"
#include "prov.h"
#include "net.h"
#include "proxy.h"
#include "adv.h"
#include "prov.h"
struct prov_link {
uint16_t conn_handle;
const struct prov_bearer_cb *cb;
void *cb_data;
struct {
uint8_t id; /* Transaction ID */
uint8_t prev_id; /* Previous Transaction ID */
uint8_t seg; /* Bit-field of unreceived segments */
uint8_t last_seg; /* Last segment (to check length) */
uint8_t fcs; /* Expected FCS value */
struct os_mbuf *buf;
} rx;
struct k_delayed_work prot_timer;
};
static struct prov_link link;
static void reset_state(void)
{
link.conn_handle = BLE_HS_CONN_HANDLE_NONE;
k_delayed_work_cancel(&link.prot_timer);
link.rx.buf = bt_mesh_proxy_get_buf();
}
static void link_closed(enum prov_bearer_link_status status)
{
const struct prov_bearer_cb *cb = link.cb;
void *cb_data = link.cb_data;
reset_state();
cb->link_closed(&pb_gatt, cb_data, status);
}
static void protocol_timeout(struct ble_npl_event *work)
{
BT_DBG("Protocol timeout");
link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT);
}
int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf)
{
BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
if (link.conn_handle != conn_handle || !link.cb) {
BT_WARN("Data for unexpected connection");
return -ENOTCONN;
}
if (buf->om_len < 1) {
BT_WARN("Too short provisioning packet (len %u)", buf->om_len);
return -EINVAL;
}
k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT);
link.cb->recv(&pb_gatt, link.cb_data, buf);
return 0;
}
int bt_mesh_pb_gatt_open(uint16_t conn_handle)
{
BT_DBG("conn %p", conn_handle);
if (link.conn_handle) {
return -EBUSY;
}
link.conn_handle = conn_handle;
k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT);
link.cb->link_opened(&pb_gatt, link.cb_data);
return 0;
}
int bt_mesh_pb_gatt_close(uint16_t conn_handle)
{
BT_DBG("conn %p", conn_handle);
if (link.conn_handle != conn_handle) {
BT_DBG("Not connected");
return -ENOTCONN;
}
link.cb->link_closed(&pb_gatt, link.cb_data,
PROV_BEARER_LINK_STATUS_SUCCESS);
reset_state();
return 0;
}
static int link_accept(const struct prov_bearer_cb *cb, void *cb_data)
{
bt_mesh_proxy_prov_enable();
bt_mesh_adv_update();
link.cb = cb;
link.cb_data = cb_data;
return 0;
}
static int buf_send(struct os_mbuf *buf, prov_bearer_send_complete_t cb,
void *cb_data)
{
if (!link.conn_handle) {
return -ENOTCONN;
}
k_delayed_work_submit(&link.prot_timer, PROTOCOL_TIMEOUT);
return bt_mesh_proxy_send(link.conn_handle, BT_MESH_PROXY_PROV, buf);
}
static void clear_tx(void)
{
/* No action */
}
void pb_gatt_init(void)
{
k_delayed_work_init(&link.prot_timer, protocol_timeout);
}
void pb_gatt_reset(void)
{
reset_state();
}
const struct prov_bearer pb_gatt = {
.type = BT_MESH_PROV_GATT,
.link_accept = link_accept,
.send = buf_send,
.clear_tx = clear_tx,
};
#endif /* MYNEWT_VAL(BLE_MESH) */

File diff suppressed because it is too large Load Diff

View File

@@ -9,16 +9,131 @@
#ifndef __PROV_H__
#define __PROV_H__
#include "prov_bearer.h"
#include "nimble/porting/nimble/include/os/os_mbuf.h"
#include "../include/mesh/mesh.h"
#include "nimble/nimble/host/src/ble_hs_conn_priv.h"
int bt_mesh_pb_adv_open(const u8_t uuid[16], u16_t net_idx, u16_t addr,
u8_t attention_duration);
#define PROV_ERR_NONE 0x00
#define PROV_ERR_NVAL_PDU 0x01
#define PROV_ERR_NVAL_FMT 0x02
#define PROV_ERR_UNEXP_PDU 0x03
#define PROV_ERR_CFM_FAILED 0x04
#define PROV_ERR_RESOURCES 0x05
#define PROV_ERR_DECRYPT 0x06
#define PROV_ERR_UNEXP_ERR 0x07
#define PROV_ERR_ADDR 0x08
void bt_mesh_pb_adv_recv(struct os_mbuf *buf);
#define AUTH_METHOD_NO_OOB 0x00
#define AUTH_METHOD_STATIC 0x01
#define AUTH_METHOD_OUTPUT 0x02
#define AUTH_METHOD_INPUT 0x03
bool bt_prov_active(void);
#define OUTPUT_OOB_BLINK 0x00
#define OUTPUT_OOB_BEEP 0x01
#define OUTPUT_OOB_VIBRATE 0x02
#define OUTPUT_OOB_NUMBER 0x03
#define OUTPUT_OOB_STRING 0x04
#define INPUT_OOB_PUSH 0x00
#define INPUT_OOB_TWIST 0x01
#define INPUT_OOB_NUMBER 0x02
#define INPUT_OOB_STRING 0x03
#define PUB_KEY_NO_OOB 0x00
#define PUB_KEY_OOB 0x01
#define PROV_INVITE 0x00
#define PROV_CAPABILITIES 0x01
#define PROV_START 0x02
#define PROV_PUB_KEY 0x03
#define PROV_INPUT_COMPLETE 0x04
#define PROV_CONFIRM 0x05
#define PROV_RANDOM 0x06
#define PROV_DATA 0x07
#define PROV_COMPLETE 0x08
#define PROV_FAILED 0x09
#define PROV_NO_PDU 0xff
#define PROV_ALG_P256 0x00
#define PROV_BUF(len) \
NET_BUF_SIMPLE(PROV_BEARER_BUF_HEADROOM + len)
enum {
WAIT_PUB_KEY, /* Waiting for local PubKey to be generated */
LINK_ACTIVE, /* Link has been opened */
WAIT_NUMBER, /* Waiting for number input from user */
WAIT_STRING, /* Waiting for string input from user */
NOTIFY_INPUT_COMPLETE, /* Notify that input has been completed. */
PROVISIONER, /* The link was opened as provisioner */
OOB_PUB_KEY, /* OOB Public key used */
PUB_KEY_SENT, /* Public key has been sent */
REMOTE_PUB_KEY, /* Remote key has been received */
INPUT_COMPLETE, /* Device input completed */
WAIT_CONFIRM, /* Wait for send confirm */
WAIT_AUTH, /* Wait for auth response */
OOB_STATIC_KEY, /* OOB Static Authentication */
NUM_FLAGS,
};
/** Provisioning role */
struct bt_mesh_prov_role {
void (*link_opened)(void);
void (*link_closed)(void);
void (*error)(uint8_t reason);
void (*input_complete)(void);
void (*op[10])(const uint8_t *data);
};
struct bt_mesh_prov_link {
ATOMIC_DEFINE(flags, NUM_FLAGS);
const struct prov_bearer *bearer;
const struct bt_mesh_prov_role *role;
uint8_t oob_method; /* Authen method */
uint8_t oob_action; /* Authen action */
uint8_t oob_size; /* Authen size */
uint8_t auth[16]; /* Authen value */
uint8_t dhkey[32]; /* Calculated DHKey */
uint8_t expect; /* Next expected PDU */
uint8_t conf[16]; /* Remote Confirmation */
uint8_t rand[16]; /* Local Random */
uint8_t conf_salt[16]; /* ConfirmationSalt */
uint8_t conf_key[16]; /* ConfirmationKey */
uint8_t conf_inputs[145]; /* ConfirmationInputs */
uint8_t prov_salt[16]; /* Provisioning Salt */
};
extern struct bt_mesh_prov_link bt_mesh_prov_link;
extern const struct bt_mesh_prov *bt_mesh_prov;
static inline int bt_mesh_prov_send(struct os_mbuf *buf,
prov_bearer_send_complete_t cb)
{
return bt_mesh_prov_link.bearer->send(buf, cb, NULL);
}
static inline void bt_mesh_prov_buf_init(struct os_mbuf *buf, uint8_t type)
{
net_buf_reserve(buf, PROV_BEARER_BUF_HEADROOM);
net_buf_simple_add_u8(buf, type);
}
int bt_mesh_prov_reset_state(void (*func)(const uint8_t key[64]));
bool bt_mesh_prov_active(void);
int bt_mesh_prov_auth(uint8_t method, uint8_t action, uint8_t size);
int bt_mesh_pb_gatt_open(uint16_t conn_handle);
int bt_mesh_pb_gatt_close(uint16_t conn_handle);
@@ -26,12 +141,14 @@ int bt_mesh_pb_gatt_recv(uint16_t conn_handle, struct os_mbuf *buf);
const struct bt_mesh_prov *bt_mesh_prov_get(void);
int bt_mesh_prov_init(const struct bt_mesh_prov *prov);
void bt_mesh_prov_reset_link(void);
void bt_mesh_prov_complete(u16_t net_idx, u16_t addr);
void bt_mesh_prov_node_added(u16_t net_idx, u16_t addr, u8_t num_elem);
void bt_mesh_prov_complete(uint16_t net_idx, uint16_t addr);
void bt_mesh_prov_reset(void);
const struct prov_bearer_cb *bt_mesh_prov_bearer_cb_get(void);
void bt_mesh_pb_adv_recv(struct os_mbuf *buf);
int bt_mesh_prov_init(const struct bt_mesh_prov *prov);
#endif

View File

@@ -0,0 +1,116 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#define PROTOCOL_TIMEOUT K_SECONDS(60)
/** @def PROV_BEARER_BUF_HEADROOM
*
* @brief Required headroom for the bearer packet buffers.
*/
#if MYNEWT_VAL(BLE_MESH_PB_GATT)
#define PROV_BEARER_BUF_HEADROOM 5
#else
#define PROV_BEARER_BUF_HEADROOM 0
#endif
enum prov_bearer_link_status {
PROV_BEARER_LINK_STATUS_SUCCESS,
PROV_BEARER_LINK_STATUS_TIMEOUT,
PROV_BEARER_LINK_STATUS_FAIL,
};
struct prov_bearer;
/** Callbacks from bearer to host */
struct prov_bearer_cb {
void (*link_opened)(const struct prov_bearer *bearer, void *cb_data);
void (*link_closed)(const struct prov_bearer *bearer, void *cb_data,
enum prov_bearer_link_status reason);
void (*error)(const struct prov_bearer *bearer, void *cb_data,
uint8_t err);
void (*recv)(const struct prov_bearer *bearer, void *cb_data,
struct os_mbuf *buf);
};
typedef void (*prov_bearer_send_complete_t)(int err, void *cb_data);
/** Provisioning bearer API */
struct prov_bearer {
/** Provisioning bearer type. */
bt_mesh_prov_bearer_t type;
/** @brief Enable link establishment as a provisionee.
*
* Prompts the bearer to make itself visible to provisioners, and
* start accepting link open messages.
*
* @param cb Bearer event callbacks used for the duration of the link.
* @param cb_data Context parameter to pass to the bearer callbacks.
*
* @return Zero on success, or (negative) error code otherwise.
*/
int (*link_accept)(const struct prov_bearer_cb *cb, void *cb_data);
/** @brief Send a packet on an established link.
*
* @param buf Payload buffer. Requires @ref
* PROV_BEARER_BUF_HEADROOM bytes of headroom.
* @param cb Callback to call when sending is complete.
* @param cb_data Callback data.
*
* @return Zero on success, or (negative) error code otherwise.
*/
int (*send)(struct os_mbuf *buf, prov_bearer_send_complete_t cb,
void *cb_data);
/** @brief Clear any ongoing transmissions, if possible.
*
* Bearers that don't support tx clearing must implement this callback
* and leave it empty.
*/
void (*clear_tx)(void);
/* Only available in provisioners: */
/** @brief Open a new link as a provisioner.
*
* Only available in provisioners. Bearers that don't support the
* provisioner role should leave this as NULL.
*
* @param uuid UUID of the node to establish a link to.
* @param timeout Protocol timeout.
* @param cb Bearer event callbacks used for the duration of the link.
* @param cb_data Context parameter to pass to the bearer callbacks.
*
* @return Zero on success, or (negative) error code otherwise.
*/
int (*link_open)(const uint8_t uuid[16], int32_t timeout,
const struct prov_bearer_cb *cb, void *cb_data);
/** @brief Close the current link.
*
* Only available in provisioners. Bearers that don't support the
* provisioner role should leave this as NULL.
*
* @param status Link status for the link close message.
*/
void (*link_close)(enum prov_bearer_link_status status);
};
extern const struct prov_bearer pb_adv;
extern const struct prov_bearer pb_gatt;
void pb_adv_init(void);
void pb_gatt_init(void);
void pb_adv_reset(void);
void pb_gatt_reset(void);

View File

@@ -0,0 +1,573 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2020 Lingao Meng
*
* SPDX-License-Identifier: Apache-2.0
*/
#define MESH_LOG_MODULE BLE_MESH_PROV_LOG
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#include "crypto.h"
#include "adv.h"
#include "../include/mesh/mesh.h"
#include "net.h"
#include "rpl.h"
#include "beacon.h"
#include "access.h"
#include "foundation.h"
#include "proxy.h"
#include "prov.h"
#include "settings.h"
static void send_pub_key(void);
static void pub_key_ready(const uint8_t *pkey);
static int reset_state(void)
{
return bt_mesh_prov_reset_state(pub_key_ready);
}
static void prov_send_fail_msg(uint8_t err)
{
struct os_mbuf *buf = PROV_BUF(2);
BT_DBG("%u", err);
bt_mesh_prov_link.expect = PROV_NO_PDU;
bt_mesh_prov_buf_init(buf, PROV_FAILED);
net_buf_simple_add_u8(buf, err);
if (bt_mesh_prov_send(buf, NULL)) {
BT_ERR("Failed to send Provisioning Failed message");
}
}
static void prov_fail(uint8_t reason)
{
/* According to Bluetooth Mesh Specification v1.0.1, Section 5.4.4, the
* provisioner just closes the link when something fails, while the
* provisionee sends the fail message, and waits for the provisioner to
* close the link.
*/
prov_send_fail_msg(reason);
}
static void prov_invite(const uint8_t *data)
{
struct os_mbuf *buf = PROV_BUF(12);
BT_DBG("Attention Duration: %u seconds", data[0]);
if (data[0]) {
bt_mesh_attention(NULL, data[0]);
}
bt_mesh_prov_link.conf_inputs[0] = data[0];
bt_mesh_prov_buf_init(buf, PROV_CAPABILITIES);
/* Number of Elements supported */
net_buf_simple_add_u8(buf, bt_mesh_elem_count());
/* Supported algorithms - FIPS P-256 Eliptic Curve */
net_buf_simple_add_be16(buf, BIT(PROV_ALG_P256));
/* Public Key Type, Only "No OOB" Public Key is supported */
net_buf_simple_add_u8(buf, PUB_KEY_NO_OOB);
/* Static OOB Type */
net_buf_simple_add_u8(buf, bt_mesh_prov->static_val ? BIT(0) : 0x00);
/* Output OOB Size */
net_buf_simple_add_u8(buf, bt_mesh_prov->output_size);
/* Output OOB Action */
net_buf_simple_add_be16(buf, bt_mesh_prov->output_actions);
/* Input OOB Size */
net_buf_simple_add_u8(buf, bt_mesh_prov->input_size);
/* Input OOB Action */
net_buf_simple_add_be16(buf, bt_mesh_prov->input_actions);
memcpy(&bt_mesh_prov_link.conf_inputs[1], &buf->om_data[1], 11);
if (bt_mesh_prov_send(buf, NULL)) {
BT_ERR("Failed to send capabilities");
return;
}
bt_mesh_prov_link.expect = PROV_START;
}
static void prov_start(const uint8_t *data)
{
BT_DBG("Algorithm: 0x%02x", data[0]);
BT_DBG("Public Key: 0x%02x", data[1]);
BT_DBG("Auth Method: 0x%02x", data[2]);
BT_DBG("Auth Action: 0x%02x", data[3]);
BT_DBG("Auth Size: 0x%02x", data[4]);
if (data[0] != PROV_ALG_P256) {
BT_ERR("Unknown algorithm 0x%02x", data[0]);
prov_fail(PROV_ERR_NVAL_FMT);
return;
}
if (data[1] != PUB_KEY_NO_OOB) {
BT_ERR("Invalid public key type: 0x%02x", data[1]);
prov_fail(PROV_ERR_NVAL_FMT);
return;
}
memcpy(&bt_mesh_prov_link.conf_inputs[12], data, 5);
bt_mesh_prov_link.expect = PROV_PUB_KEY;
if (bt_mesh_prov_auth(data[2], data[3], data[4]) < 0) {
BT_ERR("Invalid authentication method: 0x%02x; "
"action: 0x%02x; size: 0x%02x", data[2], data[3],
data[4]);
prov_fail(PROV_ERR_NVAL_FMT);
}
if (atomic_test_bit(bt_mesh_prov_link.flags, OOB_STATIC_KEY)) {
memcpy(bt_mesh_prov_link.auth + 16 - bt_mesh_prov->static_val_len,
bt_mesh_prov->static_val, bt_mesh_prov->static_val_len);
(void)memset(bt_mesh_prov_link.auth, 0,
sizeof(bt_mesh_prov_link.auth) - bt_mesh_prov->static_val_len);
}
}
static void send_confirm(void)
{
struct os_mbuf *cfm = PROV_BUF(17);
BT_DBG("ConfInputs[0] %s", bt_hex(bt_mesh_prov_link.conf_inputs, 64));
BT_DBG("ConfInputs[64] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[64], 64));
BT_DBG("ConfInputs[128] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[128], 17));
if (bt_mesh_prov_conf_salt(bt_mesh_prov_link.conf_inputs,
bt_mesh_prov_link.conf_salt)) {
BT_ERR("Unable to generate confirmation salt");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("ConfirmationSalt: %s", bt_hex(bt_mesh_prov_link.conf_salt, 16));
if (bt_mesh_prov_conf_key(bt_mesh_prov_link.dhkey, bt_mesh_prov_link.conf_salt,
bt_mesh_prov_link.conf_key)) {
BT_ERR("Unable to generate confirmation key");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("ConfirmationKey: %s", bt_hex(bt_mesh_prov_link.conf_key, 16));
if (bt_rand(bt_mesh_prov_link.rand, 16)) {
BT_ERR("Unable to generate random number");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("LocalRandom: %s", bt_hex(bt_mesh_prov_link.rand, 16));
bt_mesh_prov_buf_init(cfm, PROV_CONFIRM);
if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key, bt_mesh_prov_link.rand,
bt_mesh_prov_link.auth, net_buf_simple_add(cfm, 16))) {
BT_ERR("Unable to generate confirmation value");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
if (bt_mesh_prov_send(cfm, NULL)) {
BT_ERR("Failed to send Provisioning Confirm");
return;
}
bt_mesh_prov_link.expect = PROV_RANDOM;
}
static void send_input_complete(void)
{
struct os_mbuf *buf = PROV_BUF(1);
bt_mesh_prov_buf_init(buf, PROV_INPUT_COMPLETE);
if (bt_mesh_prov_send(buf, NULL)) {
BT_ERR("Failed to send Provisioning Input Complete");
}
bt_mesh_prov_link.expect = PROV_CONFIRM;
}
static void public_key_sent(int err, void *cb_data)
{
atomic_set_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT);
if (atomic_test_bit(bt_mesh_prov_link.flags, INPUT_COMPLETE)) {
send_input_complete();
return;
}
}
static void send_pub_key(void)
{
struct os_mbuf *buf = PROV_BUF(65);
const uint8_t *key;
key = bt_pub_key_get();
if (!key) {
BT_ERR("No public key available");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("Local Public Key: %s", bt_hex(key, 64));
bt_mesh_prov_buf_init(buf, PROV_PUB_KEY);
/* Swap X and Y halves independently to big-endian */
sys_memcpy_swap(net_buf_simple_add(buf, 32), key, 32);
sys_memcpy_swap(net_buf_simple_add(buf, 32), &key[32], 32);
/* PublicKeyRemote */
memcpy(&bt_mesh_prov_link.conf_inputs[81], &buf->om_data[1], 64);
if (bt_mesh_prov_send(buf, public_key_sent)) {
BT_ERR("Failed to send Public Key");
return;
}
if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) ||
atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING)) {
bt_mesh_prov_link.expect = PROV_NO_PDU; /* Wait for input */
} else {
bt_mesh_prov_link.expect = PROV_CONFIRM;
}
}
static void prov_dh_key_cb(const uint8_t dhkey[32])
{
BT_DBG("%p", dhkey);
if (!dhkey) {
BT_ERR("DHKey generation failed");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, 32);
BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, 32));
send_pub_key();
}
static void prov_dh_key_gen(void)
{
uint8_t remote_pk_le[64], *remote_pk;
remote_pk = &bt_mesh_prov_link.conf_inputs[17];
/* Copy remote key in little-endian for bt_dh_key_gen().
* X and Y halves are swapped independently. The bt_dh_key_gen()
* will also take care of validating the remote public key.
*/
sys_memcpy_swap(remote_pk_le, remote_pk, 32);
sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32);
if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) {
BT_ERR("Failed to generate DHKey");
prov_fail(PROV_ERR_UNEXP_ERR);
}
}
static void prov_pub_key(const uint8_t *data)
{
BT_DBG("Remote Public Key: %s", bt_hex(data, 64));
/* PublicKeyProvisioner */
memcpy(&bt_mesh_prov_link.conf_inputs[17], data, 64);
if (!bt_pub_key_get()) {
/* Clear retransmit timer */
bt_mesh_prov_link.bearer->clear_tx();
atomic_set_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY);
BT_WARN("Waiting for local public key");
return;
}
prov_dh_key_gen();
}
static void pub_key_ready(const uint8_t *pkey)
{
if (!pkey) {
BT_WARN("Public key not available");
return;
}
BT_DBG("Local public key ready");
if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY)) {
prov_dh_key_gen();
}
}
static void notify_input_complete(void)
{
if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags,
NOTIFY_INPUT_COMPLETE) &&
bt_mesh_prov->input_complete) {
bt_mesh_prov->input_complete();
}
}
static void send_random(void)
{
struct os_mbuf *rnd = PROV_BUF(17);
bt_mesh_prov_buf_init(rnd, PROV_RANDOM);
net_buf_simple_add_mem(rnd, bt_mesh_prov_link.rand, 16);
if (bt_mesh_prov_send(rnd, NULL)) {
BT_ERR("Failed to send Provisioning Random");
return;
}
bt_mesh_prov_link.expect = PROV_DATA;
}
static void prov_random(const uint8_t *data)
{
uint8_t conf_verify[16];
BT_DBG("Remote Random: %s", bt_hex(data, 16));
if (!memcmp(data, bt_mesh_prov_link.rand, 16)) {
BT_ERR("Random value is identical to ours, rejecting.");
prov_fail(PROV_ERR_CFM_FAILED);
return;
}
if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key, data,
bt_mesh_prov_link.auth, conf_verify)) {
BT_ERR("Unable to calculate confirmation verification");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
if (memcmp(conf_verify, bt_mesh_prov_link.conf, 16)) {
BT_ERR("Invalid confirmation value");
BT_DBG("Received: %s", bt_hex(bt_mesh_prov_link.conf, 16));
BT_DBG("Calculated: %s", bt_hex(conf_verify, 16));
prov_fail(PROV_ERR_CFM_FAILED);
return;
}
if (bt_mesh_prov_salt(bt_mesh_prov_link.conf_salt, data,
bt_mesh_prov_link.rand, bt_mesh_prov_link.prov_salt)) {
BT_ERR("Failed to generate provisioning salt");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("ProvisioningSalt: %s", bt_hex(bt_mesh_prov_link.prov_salt, 16));
send_random();
}
static void prov_confirm(const uint8_t *data)
{
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
memcpy(bt_mesh_prov_link.conf, data, 16);
notify_input_complete();
send_confirm();
}
static inline bool is_pb_gatt(void)
{
return bt_mesh_prov_link.bearer &&
bt_mesh_prov_link.bearer->type == BT_MESH_PROV_GATT;
}
static void prov_data(const uint8_t *data)
{
struct os_mbuf *msg = PROV_BUF(1);
uint8_t session_key[16];
uint8_t nonce[13];
uint8_t dev_key[16];
uint8_t pdu[25];
uint8_t flags;
uint32_t iv_index;
uint16_t addr;
uint16_t net_idx;
int err;
bool identity_enable;
BT_DBG("");
err = bt_mesh_session_key(bt_mesh_prov_link.dhkey,
bt_mesh_prov_link.prov_salt, session_key);
if (err) {
BT_ERR("Unable to generate session key");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("SessionKey: %s", bt_hex(session_key, 16));
err = bt_mesh_prov_nonce(bt_mesh_prov_link.dhkey,
bt_mesh_prov_link.prov_salt, nonce);
if (err) {
BT_ERR("Unable to generate session nonce");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("Nonce: %s", bt_hex(nonce, 13));
err = bt_mesh_prov_decrypt(session_key, nonce, data, pdu);
if (err) {
BT_ERR("Unable to decrypt provisioning data");
prov_fail(PROV_ERR_DECRYPT);
return;
}
err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey,
bt_mesh_prov_link.prov_salt, dev_key);
if (err) {
BT_ERR("Unable to generate device key");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("DevKey: %s", bt_hex(dev_key, 16));
net_idx = sys_get_be16(&pdu[16]);
flags = pdu[18];
iv_index = sys_get_be32(&pdu[19]);
addr = sys_get_be16(&pdu[23]);
BT_DBG("net_idx %u iv_index 0x%08x, addr 0x%04x",
net_idx, iv_index, addr);
bt_mesh_prov_buf_init(msg, PROV_COMPLETE);
if (bt_mesh_prov_send(msg, NULL)) {
BT_ERR("Failed to send Provisioning Complete");
return;
}
/* Ignore any further PDUs on this link */
bt_mesh_prov_link.expect = PROV_NO_PDU;
/* Store info, since bt_mesh_provision() will end up clearing it */
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
identity_enable = is_pb_gatt();
} else {
identity_enable = false;
}
err = bt_mesh_provision(pdu, net_idx, flags, iv_index, addr, dev_key);
if (err) {
BT_ERR("Failed to provision (err %d)", err);
return;
}
/* After PB-GATT provisioning we should start advertising
* using Node Identity.
*/
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && identity_enable) {
bt_mesh_proxy_identity_enable();
}
}
static void local_input_complete(void)
{
if (atomic_test_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT)) {
send_input_complete();
} else {
atomic_set_bit(bt_mesh_prov_link.flags, INPUT_COMPLETE);
}
}
static void prov_link_closed(void)
{
reset_state();
}
static void prov_link_opened(void)
{
bt_mesh_prov_link.expect = PROV_INVITE;
}
static const struct bt_mesh_prov_role role_device = {
.input_complete = local_input_complete,
.link_opened = prov_link_opened,
.link_closed = prov_link_closed,
.error = prov_fail,
.op = {
[PROV_INVITE] = prov_invite,
[PROV_START] = prov_start,
[PROV_PUB_KEY] = prov_pub_key,
[PROV_CONFIRM] = prov_confirm,
[PROV_RANDOM] = prov_random,
[PROV_DATA] = prov_data,
},
};
int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers)
{
BT_DBG("bt_mesh_prov_enable");
if (bt_mesh_is_provisioned()) {
return -EALREADY;
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&
(bearers & BT_MESH_PROV_ADV)) {
pb_adv.link_accept(bt_mesh_prov_bearer_cb_get(), NULL);
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
(bearers & BT_MESH_PROV_GATT)) {
pb_gatt.link_accept(bt_mesh_prov_bearer_cb_get(), NULL);
}
BT_DBG("bt_mesh_prov_link.role = &role_device");
bt_mesh_prov_link.role = &role_device;
return 0;
}
int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers)
{
if (bt_mesh_is_provisioned()) {
return -EALREADY;
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) &&
(bearers & BT_MESH_PROV_ADV)) {
bt_mesh_beacon_disable();
bt_mesh_scan_disable();
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
(bearers & BT_MESH_PROV_GATT)) {
bt_mesh_proxy_prov_disable(true);
}
return 0;
}
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,750 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2020 Lingao Meng
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_PROV_LOG
#if MYNEWT_VAL(BLE_MESH)
#include "crypto.h"
#include "adv.h"
#include "../include/mesh/mesh.h"
#include "net.h"
#include "rpl.h"
#include "beacon.h"
#include "access.h"
#include "foundation.h"
#include "proxy.h"
#include "prov.h"
#include "settings.h"
static struct {
struct bt_mesh_cdb_node *node;
uint16_t addr;
uint16_t net_idx;
uint8_t attention_duration;
uint8_t uuid[16];
} prov_device;
static void send_pub_key(void);
static void prov_dh_key_gen(void);
static void pub_key_ready(const uint8_t *pkey);
static int reset_state(void)
{
#if MYNEWT_VAL(BLE_MESH_CDB)
if (prov_device.node != NULL) {
bt_mesh_cdb_node_del(prov_device.node, false);
}
#endif
return bt_mesh_prov_reset_state(pub_key_ready);
}
static void prov_link_close(enum prov_bearer_link_status status)
{
BT_DBG("%u", status);
bt_mesh_prov_link.expect = PROV_NO_PDU;
bt_mesh_prov_link.bearer->link_close(status);
}
static void prov_fail(uint8_t reason)
{
/* According to Bluetooth Mesh Specification v1.0.1, Section 5.4.4, the
* provisioner just closes the link when something fails, while the
* provisionee sends the fail message, and waits for the provisioner to
* close the link.
*/
prov_link_close(PROV_BEARER_LINK_STATUS_FAIL);
}
static void send_invite(void)
{
struct os_mbuf *inv = PROV_BUF(2);
BT_DBG("");
bt_mesh_prov_buf_init(inv, PROV_INVITE);
net_buf_simple_add_u8(inv, prov_device.attention_duration);
bt_mesh_prov_link.conf_inputs[0] = prov_device.attention_duration;
if (bt_mesh_prov_send(inv, NULL)) {
BT_ERR("Failed to send invite");
return;
}
bt_mesh_prov_link.expect = PROV_CAPABILITIES;
}
static void start_sent(int err, void *cb_data)
{
if (!bt_pub_key_get()) {
atomic_set_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY);
BT_WARN("Waiting for local public key");
} else {
send_pub_key();
}
}
static void send_start(void)
{
BT_DBG("");
uint8_t method, action;
struct os_mbuf *start = PROV_BUF(6);
const uint8_t *data = &bt_mesh_prov_link.conf_inputs[1 + 3];
bt_mesh_prov_buf_init(start, PROV_START);
net_buf_simple_add_u8(start, PROV_ALG_P256);
if (atomic_test_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY) &&
*data == PUB_KEY_OOB) {
net_buf_simple_add_u8(start, PUB_KEY_OOB);
atomic_set_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY);
} else {
net_buf_simple_add_u8(start, PUB_KEY_NO_OOB);
}
if (bt_mesh_prov_link.oob_method == AUTH_METHOD_INPUT) {
method = AUTH_METHOD_OUTPUT;
if (bt_mesh_prov_link.oob_action == INPUT_OOB_STRING) {
action = OUTPUT_OOB_STRING;
} else {
action = OUTPUT_OOB_NUMBER;
}
} else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_OUTPUT) {
method = AUTH_METHOD_INPUT;
if (bt_mesh_prov_link.oob_action == OUTPUT_OOB_STRING) {
action = INPUT_OOB_STRING;
} else {
action = INPUT_OOB_NUMBER;
}
} else {
method = bt_mesh_prov_link.oob_method;
action = 0x00;
}
net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_method);
net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_action);
net_buf_simple_add_u8(start, bt_mesh_prov_link.oob_size);
memcpy(&bt_mesh_prov_link.conf_inputs[12], &start->om_data[1], 5);
if (bt_mesh_prov_auth(method, action, bt_mesh_prov_link.oob_size) < 0) {
BT_ERR("Invalid authentication method: 0x%02x; "
"action: 0x%02x; size: 0x%02x", method,
action, bt_mesh_prov_link.oob_size);
return;
}
if (bt_mesh_prov_send(start, start_sent)) {
BT_ERR("Failed to send Provisioning Start");
return;
}
}
static bool prov_check_method(struct bt_mesh_dev_capabilities *caps)
{
if (bt_mesh_prov_link.oob_method == AUTH_METHOD_STATIC) {
if (!caps->static_oob) {
BT_WARN("Device not support OOB static authentication provisioning");
return false;
}
} else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_INPUT) {
if (bt_mesh_prov_link.oob_size > caps->input_size) {
BT_WARN("The required input length (0x%02x) "
"exceeds the device capacity (0x%02x)",
bt_mesh_prov_link.oob_size, caps->input_size);
return false;
}
if (!(BIT(bt_mesh_prov_link.oob_action) & caps->input_actions)) {
BT_WARN("The required input action (0x%02x) "
"not supported by the device (0x%02x)",
bt_mesh_prov_link.oob_action, caps->input_actions);
return false;
}
if (bt_mesh_prov_link.oob_action == INPUT_OOB_STRING) {
if (!bt_mesh_prov->output_string) {
BT_WARN("Not support output string");
return false;
}
} else {
if (!bt_mesh_prov->output_number) {
BT_WARN("Not support output number");
return false;
}
}
} else if (bt_mesh_prov_link.oob_method == AUTH_METHOD_OUTPUT) {
if (bt_mesh_prov_link.oob_size > caps->output_size) {
BT_WARN("The required output length (0x%02x) "
"exceeds the device capacity (0x%02x)",
bt_mesh_prov_link.oob_size, caps->output_size);
return false;
}
if (!(BIT(bt_mesh_prov_link.oob_action) & caps->output_actions)) {
BT_WARN("The required output action (0x%02x) "
"not supported by the device (0x%02x)",
bt_mesh_prov_link.oob_action, caps->output_actions);
return false;
}
if (!bt_mesh_prov->input) {
BT_WARN("Not support input");
return false;
}
}
return true;
}
static void prov_capabilities(const uint8_t *data)
{
struct bt_mesh_dev_capabilities caps;
caps.elem_count = data[0];
BT_DBG("Elements: %u", caps.elem_count);
caps.algorithms = sys_get_be16(&data[1]);
BT_DBG("Algorithms: %u", caps.algorithms);
caps.pub_key_type = data[3];
caps.static_oob = data[4];
caps.output_size = data[5];
BT_DBG("Public Key Type: 0x%02x", caps.pub_key_type);
BT_DBG("Static OOB Type: 0x%02x", caps.static_oob);
BT_DBG("Output OOB Size: %u", caps.output_size);
caps.output_actions = (bt_mesh_output_action_t)data[6];
caps.input_size = data[8];
caps.input_actions = (bt_mesh_input_action_t)data[9];
BT_DBG("Output OOB Action: 0x%04x", caps.output_actions);
BT_DBG("Input OOB Size: %u", caps.input_size);
BT_DBG("Input OOB Action: 0x%04x", caps.input_actions);
if (data[0] == 0) {
BT_ERR("Invalid number of elements");
prov_fail(PROV_ERR_NVAL_FMT);
return;
}
#if MYNEWT_VAL(BLE_MESH_CDB)
prov_device.node =
bt_mesh_cdb_node_alloc(prov_device.uuid,
prov_device.addr, data[0],
prov_device.net_idx);
if (prov_device.node == NULL) {
BT_ERR("Failed allocating node 0x%04x", prov_device.addr);
prov_fail(PROV_ERR_RESOURCES);
return;
}
#endif
memcpy(&bt_mesh_prov_link.conf_inputs[1], data, 11);
if (bt_mesh_prov->capabilities) {
bt_mesh_prov->capabilities(&caps);
}
if (!prov_check_method(&caps)) {
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
send_start();
}
static void send_confirm(void)
{
struct os_mbuf *cfm = PROV_BUF(17);
BT_DBG("ConfInputs[0] %s", bt_hex(bt_mesh_prov_link.conf_inputs, 64));
BT_DBG("ConfInputs[64] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[64], 64));
BT_DBG("ConfInputs[128] %s", bt_hex(&bt_mesh_prov_link.conf_inputs[128], 17));
if (bt_mesh_prov_conf_salt(bt_mesh_prov_link.conf_inputs,
bt_mesh_prov_link.conf_salt)) {
BT_ERR("Unable to generate confirmation salt");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("ConfirmationSalt: %s", bt_hex(bt_mesh_prov_link.conf_salt, 16));
if (bt_mesh_prov_conf_key(bt_mesh_prov_link.dhkey,
bt_mesh_prov_link.conf_salt, bt_mesh_prov_link.conf_key)) {
BT_ERR("Unable to generate confirmation key");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("ConfirmationKey: %s", bt_hex(bt_mesh_prov_link.conf_key, 16));
if (bt_rand(bt_mesh_prov_link.rand, 16)) {
BT_ERR("Unable to generate random number");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("LocalRandom: %s", bt_hex(bt_mesh_prov_link.rand, 16));
bt_mesh_prov_buf_init(cfm, PROV_CONFIRM);
if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key,
bt_mesh_prov_link.rand, bt_mesh_prov_link.auth,
net_buf_simple_add(cfm, 16))) {
BT_ERR("Unable to generate confirmation value");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
if (bt_mesh_prov_send(cfm, NULL)) {
BT_ERR("Failed to send Provisioning Confirm");
return;
}
bt_mesh_prov_link.expect = PROV_CONFIRM;
}
static void public_key_sent(int err, void *cb_data)
{
atomic_set_bit(bt_mesh_prov_link.flags, PUB_KEY_SENT);
if (atomic_test_bit(bt_mesh_prov_link.flags, OOB_PUB_KEY) &&
atomic_test_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY)) {
prov_dh_key_gen();
return;
}
bt_mesh_prov_link.expect = PROV_PUB_KEY;
}
static void send_pub_key(void)
{
struct os_mbuf *buf = PROV_BUF(65);
const uint8_t *key;
key = bt_pub_key_get();
if (!key) {
BT_ERR("No public key available");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("Local Public Key: %s", bt_hex(key, 64));
bt_mesh_prov_buf_init(buf, PROV_PUB_KEY);
/* Swap X and Y halves independently to big-endian */
sys_memcpy_swap(net_buf_simple_add(buf, 32), key, 32);
sys_memcpy_swap(net_buf_simple_add(buf, 32), &key[32], 32);
/* PublicKeyProvisioner */
memcpy(&bt_mesh_prov_link.conf_inputs[17], &buf->om_databuf[1], 64);
if (bt_mesh_prov_send(buf, public_key_sent)) {
BT_ERR("Failed to send Public Key");
return;
}
}
static void prov_dh_key_cb(const uint8_t dhkey[32])
{
BT_DBG("%p", dhkey);
if (!dhkey) {
BT_ERR("DHKey generation failed");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
sys_memcpy_swap(bt_mesh_prov_link.dhkey, dhkey, 32);
BT_DBG("DHkey: %s", bt_hex(bt_mesh_prov_link.dhkey, 32));
if (atomic_test_bit(bt_mesh_prov_link.flags, WAIT_STRING) ||
atomic_test_bit(bt_mesh_prov_link.flags, WAIT_NUMBER) ||
atomic_test_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE)) {
atomic_set_bit(bt_mesh_prov_link.flags, WAIT_CONFIRM);
return;
}
send_confirm();
}
static void prov_dh_key_gen(void)
{
uint8_t remote_pk_le[64], *remote_pk;
remote_pk = &bt_mesh_prov_link.conf_inputs[81];
/* Copy remote key in little-endian for bt_dh_key_gen().
* X and Y halves are swapped independently. The bt_dh_key_gen()
* will also take care of validating the remote public key.
*/
sys_memcpy_swap(remote_pk_le, remote_pk, 32);
sys_memcpy_swap(&remote_pk_le[32], &remote_pk[32], 32);
if (bt_dh_key_gen(remote_pk_le, prov_dh_key_cb)) {
BT_ERR("Failed to generate DHKey");
prov_fail(PROV_ERR_UNEXP_ERR);
}
if (atomic_test_bit(bt_mesh_prov_link.flags, NOTIFY_INPUT_COMPLETE)) {
bt_mesh_prov_link.expect = PROV_INPUT_COMPLETE;
}
}
static void prov_pub_key(const uint8_t *data)
{
BT_DBG("Remote Public Key: %s", bt_hex(data, 64));
atomic_set_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY);
/* PublicKeyDevice */
memcpy(&bt_mesh_prov_link.conf_inputs[81], data, 64);
bt_mesh_prov_link.bearer->clear_tx();
prov_dh_key_gen();
}
static void pub_key_ready(const uint8_t *pkey)
{
if (!pkey) {
BT_WARN("Public key not available");
return;
}
BT_DBG("Local public key ready");
if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_PUB_KEY)) {
send_pub_key();
}
}
static void notify_input_complete(void)
{
if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags,
NOTIFY_INPUT_COMPLETE) &&
bt_mesh_prov->input_complete) {
bt_mesh_prov->input_complete();
}
}
static void prov_input_complete(const uint8_t *data)
{
BT_DBG("");
notify_input_complete();
if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_CONFIRM)) {
send_confirm();
}
}
static void send_prov_data(void)
{
struct os_mbuf *pdu = PROV_BUF(34);
#if MYNEWT_VAL(BLE_MESH_CDB)
struct bt_mesh_cdb_subnet *sub;
#endif
uint8_t session_key[16];
uint8_t nonce[13];
int err;
err = bt_mesh_session_key(bt_mesh_prov_link.dhkey,
bt_mesh_prov_link.prov_salt, session_key);
if (err) {
BT_ERR("Unable to generate session key");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("SessionKey: %s", bt_hex(session_key, 16));
err = bt_mesh_prov_nonce(bt_mesh_prov_link.dhkey,
bt_mesh_prov_link.prov_salt, nonce);
if (err) {
BT_ERR("Unable to generate session nonce");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("Nonce: %s", bt_hex(nonce, 13));
err = bt_mesh_dev_key(bt_mesh_prov_link.dhkey,
bt_mesh_prov_link.prov_salt, prov_device.node->dev_key);
if (err) {
BT_ERR("Unable to generate device key");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("DevKey: %s", bt_hex(prov_device.node->dev_key, 16));
#if MYNEWT_VAL(BLE_MESH_CDB)
sub = bt_mesh_cdb_subnet_get(prov_device.node->net_idx);
if (sub == NULL) {
BT_ERR("No subnet with net_idx %u",
prov_device.node->net_idx);
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
#endif
bt_mesh_prov_buf_init(pdu, PROV_DATA);
#if MYNEWT_VAL(BLE_MESH_CDB)
net_buf_simple_add_mem(pdu, sub->keys[sub->kr_flag].net_key, 16);
net_buf_simple_add_be16(pdu, prov_device.node->net_idx);
net_buf_simple_add_u8(pdu, bt_mesh_cdb_subnet_flags(sub));
net_buf_simple_add_be32(pdu, bt_mesh_cdb.iv_index);
#endif
net_buf_simple_add_be16(pdu, prov_device.node->addr);
net_buf_simple_add(pdu, 8); /* For MIC */
BT_DBG("net_idx %u, iv_index 0x%08x, addr 0x%04x",
prov_device.node->net_idx, bt_mesh.iv_index,
prov_device.node->addr);
err = bt_mesh_prov_encrypt(session_key, nonce, &pdu->om_data[1],
&pdu->om_data[1]);
if (err) {
BT_ERR("Unable to encrypt provisioning data");
prov_fail(PROV_ERR_DECRYPT);
return;
}
if (bt_mesh_prov_send(pdu, NULL)) {
BT_ERR("Failed to send Provisioning Data");
return;
}
bt_mesh_prov_link.expect = PROV_COMPLETE;
}
static void prov_complete(const uint8_t *data)
{
struct bt_mesh_cdb_node *node = prov_device.node;
BT_DBG("key %s, net_idx %u, num_elem %u, addr 0x%04x",
bt_hex(node->dev_key, 16), node->net_idx, node->num_elem,
node->addr);
#if MYNEWT_VAL(BLE_MESH_CDB)
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_cdb_node(node);
}
#endif
prov_device.node = NULL;
prov_link_close(PROV_BEARER_LINK_STATUS_SUCCESS);
if (bt_mesh_prov->node_added) {
bt_mesh_prov->node_added(node->net_idx, node->uuid, node->addr,
node->num_elem);
}
}
static void send_random(void)
{
struct os_mbuf *rnd = PROV_BUF(17);
bt_mesh_prov_buf_init(rnd, PROV_RANDOM);
net_buf_simple_add_mem(rnd, bt_mesh_prov_link.rand, 16);
if (bt_mesh_prov_send(rnd, NULL)) {
BT_ERR("Failed to send Provisioning Random");
return;
}
bt_mesh_prov_link.expect = PROV_RANDOM;
}
static void prov_random(const uint8_t *data)
{
uint8_t conf_verify[16];
BT_DBG("Remote Random: %s", bt_hex(data, 16));
if (!memcmp(data, bt_mesh_prov_link.rand, 16)) {
BT_ERR("Random value is identical to ours, rejecting.");
prov_fail(PROV_ERR_CFM_FAILED);
return;
}
if (bt_mesh_prov_conf(bt_mesh_prov_link.conf_key,
data, bt_mesh_prov_link.auth, conf_verify)) {
BT_ERR("Unable to calculate confirmation verification");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
if (memcmp(conf_verify, bt_mesh_prov_link.conf, 16)) {
BT_ERR("Invalid confirmation value");
BT_DBG("Received: %s", bt_hex(bt_mesh_prov_link.conf, 16));
BT_DBG("Calculated: %s", bt_hex(conf_verify, 16));
prov_fail(PROV_ERR_CFM_FAILED);
return;
}
if (bt_mesh_prov_salt(bt_mesh_prov_link.conf_salt,
bt_mesh_prov_link.rand, data, bt_mesh_prov_link.prov_salt)) {
BT_ERR("Failed to generate provisioning salt");
prov_fail(PROV_ERR_UNEXP_ERR);
return;
}
BT_DBG("ProvisioningSalt: %s", bt_hex(bt_mesh_prov_link.prov_salt, 16));
send_prov_data();
}
static void prov_confirm(const uint8_t *data)
{
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
memcpy(bt_mesh_prov_link.conf, data, 16);
send_random();
}
static void prov_failed(const uint8_t *data)
{
BT_WARN("Error: 0x%02x", data[0]);
reset_state();
}
static void local_input_complete(void)
{
if (atomic_test_and_clear_bit(bt_mesh_prov_link.flags, WAIT_CONFIRM)) {
send_confirm();
}
}
static void prov_link_closed(void)
{
reset_state();
}
static void prov_link_opened(void)
{
send_invite();
}
static const struct bt_mesh_prov_role role_provisioner = {
.input_complete = local_input_complete,
.link_opened = prov_link_opened,
.link_closed = prov_link_closed,
.error = prov_fail,
.op = {
[PROV_CAPABILITIES] = prov_capabilities,
[PROV_PUB_KEY] = prov_pub_key,
[PROV_INPUT_COMPLETE] = prov_input_complete,
[PROV_CONFIRM] = prov_confirm,
[PROV_RANDOM] = prov_random,
[PROV_COMPLETE] = prov_complete,
[PROV_FAILED] = prov_failed,
},
};
static void prov_set_method(uint8_t method, uint8_t action, uint8_t size)
{
bt_mesh_prov_link.oob_method = method;
bt_mesh_prov_link.oob_action = action;
bt_mesh_prov_link.oob_size = size;
}
int bt_mesh_auth_method_set_input(bt_mesh_input_action_t action, uint8_t size)
{
if (!action || !size || size > 8) {
return -EINVAL;
}
prov_set_method(AUTH_METHOD_INPUT, find_msb_set(action) - 1, size);
return 0;
}
int bt_mesh_auth_method_set_output(bt_mesh_output_action_t action, uint8_t size)
{
if (!action || !size || size > 8) {
return -EINVAL;
}
prov_set_method(AUTH_METHOD_OUTPUT, find_msb_set(action) - 1, size);
return 0;
}
int bt_mesh_auth_method_set_static(const uint8_t *static_val, uint8_t size)
{
if (!size || !static_val || size > 16) {
return -EINVAL;
}
prov_set_method(AUTH_METHOD_STATIC, 0, 0);
memcpy(bt_mesh_prov_link.auth + 16 - size, static_val, size);
if (size < 16) {
(void)memset(bt_mesh_prov_link.auth, 0,
sizeof(bt_mesh_prov_link.auth) - size);
}
return 0;
}
int bt_mesh_auth_method_set_none(void)
{
prov_set_method(AUTH_METHOD_NO_OOB, 0, 0);
return 0;
}
int bt_mesh_prov_remote_pub_key_set(const uint8_t public_key[64])
{
if (public_key == NULL) {
return -EINVAL;
}
if (atomic_test_and_set_bit(bt_mesh_prov_link.flags, REMOTE_PUB_KEY)) {
return -EALREADY;
}
/* Swap X and Y halves independently to big-endian */
memcpy(&bt_mesh_prov_link.conf_inputs[81], public_key, 32);
memcpy(&bt_mesh_prov_link.conf_inputs[81 + 32], &public_key[32], 32);
return 0;
}
#if defined(CONFIG_BT_MESH_PB_ADV)
int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
uint8_t attention_duration)
{
int err;
if (atomic_test_and_set_bit(bt_mesh_prov_link.flags, LINK_ACTIVE)) {
return -EBUSY;
}
atomic_set_bit(bt_mesh_prov_link.flags, PROVISIONER);
memcpy(prov_device.uuid, uuid, 16);
prov_device.addr = addr;
prov_device.net_idx = net_idx;
prov_device.attention_duration = attention_duration;
bt_mesh_prov_link.bearer = &pb_adv;
bt_mesh_prov_link.role = &role_provisioner;
err = bt_mesh_prov_link.bearer->link_open(prov_device.uuid, PROTOCOL_TIMEOUT,
bt_mesh_prov_bearer_cb_get(), NULL);
if (err) {
atomic_clear_bit(bt_mesh_prov_link.flags, LINK_ACTIVE);
}
return err;
}
#endif
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,10 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
uint8_t attention_duration);

View File

@@ -21,6 +21,7 @@
#include "mesh_priv.h"
#include "adv.h"
#include "net.h"
#include "rpl.h"
#include "prov.h"
#include "beacon.h"
#include "foundation.h"
@@ -30,6 +31,9 @@
#define PDU_TYPE(data) (data[0] & BIT_MASK(6))
#define PDU_SAR(data) (data[0] >> 6)
#define BT_UUID_16_ENCODE(w16) \
(((w16) >> 0) & 0xFF), \
(((w16) >> 8) & 0xFF)
/* Mesh Profile 1.0 Section 6.6:
* "The timeout for the SAR transfer is 20 seconds. When the timeout
* expires, the Proxy Server shall disconnect."
@@ -112,14 +116,14 @@ static bool prov_fast_adv;
static struct bt_mesh_proxy_client {
uint16_t conn_handle;
u16_t filter[MYNEWT_VAL(BLE_MESH_PROXY_FILTER_SIZE)];
uint16_t filter[MYNEWT_VAL(BLE_MESH_PROXY_FILTER_SIZE)];
enum __packed {
NONE,
WHITELIST,
BLACKLIST,
PROV,
} filter_type;
u8_t msg_type;
uint8_t msg_type;
#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
struct ble_npl_callout send_beacons;
#endif
@@ -129,6 +133,9 @@ static struct bt_mesh_proxy_client {
[0 ... (MYNEWT_VAL(BLE_MAX_CONNECTIONS) - 1)] = { 0 },
};
static sys_slist_t idle_waiters;
static atomic_t pending_notifications;
/* Track which service is enabled */
static enum {
MESH_GATT_NONE,
@@ -197,15 +204,15 @@ static struct bt_mesh_proxy_client *find_client(uint16_t conn_handle)
#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
/* Next subnet in queue to be advertised */
static int next_idx;
static struct bt_mesh_subnet *beacon_sub;
static int proxy_segment_and_send(uint16_t conn_handle, u8_t type,
static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type,
struct os_mbuf *msg);
static int filter_set(struct bt_mesh_proxy_client *client,
struct os_mbuf *buf)
{
u8_t type;
uint8_t type;
if (buf->om_len < 1) {
BT_WARN("Too short Filter Set message");
@@ -232,7 +239,7 @@ static int filter_set(struct bt_mesh_proxy_client *client,
return 0;
}
static void filter_add(struct bt_mesh_proxy_client *client, u16_t addr)
static void filter_add(struct bt_mesh_proxy_client *client, uint16_t addr)
{
int i;
@@ -256,7 +263,7 @@ static void filter_add(struct bt_mesh_proxy_client *client, u16_t addr)
}
}
static void filter_remove(struct bt_mesh_proxy_client *client, u16_t addr)
static void filter_remove(struct bt_mesh_proxy_client *client, uint16_t addr)
{
int i;
@@ -283,7 +290,7 @@ static void send_filter_status(struct bt_mesh_proxy_client *client,
.ctx = &rx->ctx,
.src = bt_mesh_primary_addr(),
};
u16_t filter_size;
uint16_t filter_size;
int i, err;
/* Configuration messages always have dst unassigned */
@@ -325,7 +332,7 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client)
{
struct os_mbuf *buf = NET_BUF_SIMPLE(29);
struct bt_mesh_net_rx rx;
u8_t opcode;
uint8_t opcode;
int err;
err = bt_mesh_net_decode(client->buf, BT_MESH_NET_IF_PROXY_CFG,
@@ -335,8 +342,16 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client)
goto done;
}
rx.local_match = 1U;
if (bt_mesh_rpl_check(&rx, NULL)) {
BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x",
rx.ctx.addr, rx.ctx.recv_dst, rx.seq);
goto done;
}
/* Remove network headers */
net_buf_simple_pull(buf, BT_MESH_NET_HDR_LEN);
net_buf_simple_pull_mem(buf, BT_MESH_NET_HDR_LEN);
BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
@@ -353,7 +368,7 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client)
break;
case CFG_FILTER_ADD:
while (buf->om_len >= 2) {
u16_t addr;
uint16_t addr;
addr = net_buf_simple_pull_be16(buf);
filter_add(client, addr);
@@ -362,7 +377,7 @@ static void proxy_cfg(struct bt_mesh_proxy_client *client)
break;
case CFG_FILTER_REMOVE:
while (buf->om_len >= 2) {
u16_t addr;
uint16_t addr;
addr = net_buf_simple_pull_be16(buf);
filter_remove(client, addr);
@@ -391,21 +406,20 @@ static int beacon_send(uint16_t conn_handle, struct bt_mesh_subnet *sub)
return rc;
}
static int send_beacon_cb(struct bt_mesh_subnet *sub, void *cb_data)
{
struct bt_mesh_proxy_client *client = cb_data;
return beacon_send(client->conn_handle, sub);
}
static void proxy_send_beacons(struct ble_npl_event *work)
{
struct bt_mesh_proxy_client *client;
int i;
client = ble_npl_event_get_arg(work);
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) {
beacon_send(client->conn_handle, sub);
}
}
(void)bt_mesh_subnet_find(send_beacon_cb, client);
}
static void proxy_sar_timeout(struct ble_npl_event *work)
@@ -431,12 +445,7 @@ void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub)
if (!sub) {
/* NULL means we send on all subnets */
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
if (bt_mesh.sub[i].net_idx != BT_MESH_KEY_UNUSED) {
bt_mesh_proxy_beacon_send(&bt_mesh.sub[i]);
}
}
bt_mesh_subnet_foreach(bt_mesh_proxy_beacon_send);
return;
}
@@ -447,13 +456,17 @@ void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub)
}
}
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub)
static void node_id_start(struct bt_mesh_subnet *sub)
{
sub->node_id = BT_MESH_NODE_IDENTITY_RUNNING;
sub->node_id_start = k_uptime_get_32();
}
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub)
{
node_id_start(sub);
/* Prioritize the recently enabled subnet */
next_idx = sub - bt_mesh.sub;
beacon_sub = sub;
}
void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub)
@@ -464,30 +477,13 @@ void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub)
int bt_mesh_proxy_identity_enable(void)
{
int i, count = 0;
BT_DBG("");
if (!bt_mesh_is_provisioned()) {
return -EAGAIN;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (sub->node_id == BT_MESH_NODE_IDENTITY_NOT_SUPPORTED) {
continue;
}
bt_mesh_proxy_identity_start(sub);
count++;
}
if (count) {
if (bt_mesh_subnet_foreach(node_id_start)) {
bt_mesh_adv_update();
}
@@ -530,9 +526,9 @@ static void proxy_complete_pdu(struct bt_mesh_proxy_client *client)
static int proxy_recv(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
struct bt_mesh_proxy_client *client;
const u8_t *data = ctxt->om->om_data;
u16_t len = ctxt->om->om_len;
struct bt_mesh_proxy_client *client = find_client(conn_handle);
const uint8_t *data = ctxt->om->om_data;
uint16_t len = ctxt->om->om_len;
client = find_client(conn_handle);
@@ -654,7 +650,9 @@ static void proxy_connected(uint16_t conn_handle)
static void proxy_disconnected(uint16_t conn_handle, int reason)
{
int i;
bool disconnected = false;
BT_DBG("conn handle %u reason 0x%02x", conn_handle, reason);
conn_count--;
for (i = 0; i < ARRAY_SIZE(clients); i++) {
struct bt_mesh_proxy_client *client = &clients[i];
@@ -667,16 +665,11 @@ static void proxy_disconnected(uint16_t conn_handle, int reason)
k_delayed_work_cancel(&client->sar_timer);
client->conn_handle = BLE_HS_CONN_HANDLE_NONE;
conn_count--;
disconnected = true;
break;
}
}
if (disconnected) {
BT_INFO("conn_handle %d reason %d", conn_handle, reason);
bt_mesh_adv_update();
}
bt_mesh_adv_update();
}
struct os_mbuf *bt_mesh_proxy_get_buf(void)
@@ -889,7 +882,7 @@ int bt_mesh_proxy_gatt_disable(void)
return 0;
}
void bt_mesh_proxy_addr_add(struct os_mbuf *buf, u16_t addr)
void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr)
{
struct bt_mesh_proxy_client *client = NULL;
int i;
@@ -913,7 +906,7 @@ void bt_mesh_proxy_addr_add(struct os_mbuf *buf, u16_t addr)
}
static bool client_filter_match(struct bt_mesh_proxy_client *client,
u16_t addr)
uint16_t addr)
{
int i;
@@ -944,7 +937,7 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client,
return false;
}
bool bt_mesh_proxy_relay(struct os_mbuf *buf, u16_t dst)
bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst)
{
bool relayed = false;
int i;
@@ -980,9 +973,25 @@ bool bt_mesh_proxy_relay(struct os_mbuf *buf, u16_t dst)
#endif /* MYNEWT_VAL(BLE_MESH_GATT_PROXY) */
static int proxy_send(uint16_t conn_handle, const void *data, u16_t len)
static void notify_complete(void)
{
sys_snode_t *n;
if (atomic_dec(&pending_notifications) > 1) {
return;
}
BT_DBG("");
while ((n = sys_slist_get(&idle_waiters))) {
CONTAINER_OF(n, struct bt_mesh_proxy_idle_cb, n)->cb();
}
}
static int proxy_send(uint16_t conn_handle, const void *data, uint16_t len)
{
struct os_mbuf *om;
int err = 0;
BT_DBG("%u bytes: %s", len, bt_hex(data, len));
@@ -990,7 +999,8 @@ static int proxy_send(uint16_t conn_handle, const void *data, u16_t len)
if (gatt_svc == MESH_GATT_PROXY) {
om = ble_hs_mbuf_from_flat(data, len);
assert(om);
ble_gattc_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om);
err = ble_gattc_notify_custom(conn_handle, svc_handles.proxy_data_out_h, om);
notify_complete();
}
#endif
@@ -998,17 +1008,22 @@ static int proxy_send(uint16_t conn_handle, const void *data, u16_t len)
if (gatt_svc == MESH_GATT_PROV) {
om = ble_hs_mbuf_from_flat(data, len);
assert(om);
ble_gattc_notify_custom(conn_handle, svc_handles.prov_data_out_h, om);
err = ble_gattc_notify_custom(conn_handle, svc_handles.prov_data_out_h, om);
notify_complete();
}
#endif
return 0;
if (!err) {
atomic_inc(&pending_notifications);
}
return err;
}
static int proxy_segment_and_send(uint16_t conn_handle, u8_t type,
static int proxy_segment_and_send(uint16_t conn_handle, uint8_t type,
struct os_mbuf *msg)
{
u16_t mtu;
uint16_t mtu;
BT_DBG("conn_handle %d type 0x%02x len %u: %s", conn_handle, type, msg->om_len,
bt_hex(msg->om_data, msg->om_len));
@@ -1022,7 +1037,7 @@ static int proxy_segment_and_send(uint16_t conn_handle, u8_t type,
net_buf_simple_push_u8(msg, PDU_HDR(SAR_FIRST, type));
proxy_send(conn_handle, msg->om_data, mtu);
net_buf_simple_pull(msg, mtu);
net_buf_simple_pull_mem(msg, mtu);
while (msg->om_len) {
if (msg->om_len + 1 < mtu) {
@@ -1033,13 +1048,13 @@ static int proxy_segment_and_send(uint16_t conn_handle, u8_t type,
net_buf_simple_push_u8(msg, PDU_HDR(SAR_CONT, type));
proxy_send(conn_handle, msg->om_data, mtu);
net_buf_simple_pull(msg, mtu);
net_buf_simple_pull_mem(msg, mtu);
}
return 0;
}
int bt_mesh_proxy_send(uint16_t conn_handle, u8_t type,
int bt_mesh_proxy_send(uint16_t conn_handle, uint8_t type,
struct os_mbuf *msg)
{
struct bt_mesh_proxy_client *client = find_client(conn_handle);
@@ -1058,11 +1073,14 @@ int bt_mesh_proxy_send(uint16_t conn_handle, u8_t type,
}
#if (MYNEWT_VAL(BLE_MESH_PB_GATT))
static u8_t prov_svc_data[20] = { 0x27, 0x18, };
static uint8_t prov_svc_data[20] = {
BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL),
};
static const struct bt_data prov_ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x27, 0x18),
BT_DATA_BYTES(BT_DATA_UUID16_ALL,
BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL)),
BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)),
};
#endif /* PB_GATT */
@@ -1077,23 +1095,27 @@ static const struct bt_data prov_ad[] = {
#define NODE_ID_TIMEOUT K_SECONDS(CONFIG_BT_MESH_NODE_ID_TIMEOUT)
static u8_t proxy_svc_data[NODE_ID_LEN] = { 0x28, 0x18, };
static uint8_t proxy_svc_data[NODE_ID_LEN] = {
BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL),
};
static const struct bt_data node_id_ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x28, 0x18),
BT_DATA_BYTES(BT_DATA_UUID16_ALL,
BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NODE_ID_LEN),
};
static const struct bt_data net_id_ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID16_ALL, 0x28, 0x18),
BT_DATA_BYTES(BT_DATA_UUID16_ALL,
BT_UUID_16_ENCODE(BT_UUID_MESH_PROXY_VAL)),
BT_DATA(BT_DATA_SVC_DATA16, proxy_svc_data, NET_ID_LEN),
};
static int node_id_adv(struct bt_mesh_subnet *sub)
{
u8_t tmp[16];
uint8_t tmp[16];
int err;
BT_DBG("");
@@ -1109,7 +1131,8 @@ static int node_id_adv(struct bt_mesh_subnet *sub)
memcpy(tmp + 6, proxy_svc_data + 11, 8);
sys_put_be16(bt_mesh_primary_addr(), tmp + 14);
err = bt_encrypt_be(sub->keys[sub->kr_flag].identity, tmp, tmp);
err = bt_encrypt_be(sub->keys[SUBNET_KEY_TX_IDX(sub)].identity, tmp,
tmp);
if (err) {
return err;
}
@@ -1137,9 +1160,9 @@ static int net_id_adv(struct bt_mesh_subnet *sub)
proxy_svc_data[2] = ID_TYPE_NET;
BT_DBG("Advertising with NetId %s",
bt_hex(sub->keys[sub->kr_flag].net_id, 8));
bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));
memcpy(proxy_svc_data + 3, sub->keys[sub->kr_flag].net_id, 8);
memcpy(proxy_svc_data + 3, sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8);
err = bt_le_adv_start(&slow_adv_param, net_id_ad,
ARRAY_SIZE(net_id_ad), NULL, 0);
@@ -1160,60 +1183,75 @@ static bool advertise_subnet(struct bt_mesh_subnet *sub)
}
return (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING ||
bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED);
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED);
}
static struct bt_mesh_subnet *next_sub(void)
{
int i;
struct bt_mesh_subnet *sub = NULL;
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub;
sub = &bt_mesh.sub[(i + next_idx) % ARRAY_SIZE(bt_mesh.sub)];
if (advertise_subnet(sub)) {
next_idx = (next_idx + 1) % ARRAY_SIZE(bt_mesh.sub);
return sub;
if (!beacon_sub) {
beacon_sub = bt_mesh_subnet_next(NULL);
if (!beacon_sub) {
/* No valid subnets */
return NULL;
}
}
sub = beacon_sub;
do {
if (advertise_subnet(sub)) {
beacon_sub = sub;
return sub;
}
sub = bt_mesh_subnet_next(sub);
} while (sub != beacon_sub);
/* No subnets to advertise on */
return NULL;
}
static int sub_count(void)
static int sub_count_cb(struct bt_mesh_subnet *sub, void *cb_data)
{
int i, count = 0;
int *count = cb_data;
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
if (advertise_subnet(sub)) {
count++;
}
if (advertise_subnet(sub)) {
(*count)++;
}
return 0;
}
static int sub_count(void)
{
int count = 0;
(void)bt_mesh_subnet_find(sub_count_cb, &count);
return count;
}
static s32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
static int32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
{
s32_t remaining = K_FOREVER;
int32_t remaining = K_FOREVER;
int subnet_count;
BT_DBG("");
if (conn_count == CONFIG_BT_MAX_CONN) {
BT_DBG("Connectable advertising deferred (max connections)");
return remaining;
BT_DBG("Connectable advertising deferred (max connections %d)", conn_count);
return -ENOMEM;
}
sub = beacon_sub ? beacon_sub : bt_mesh_subnet_next(beacon_sub);
if (!sub) {
BT_WARN("No subnets to advertise on");
return remaining;
return -ENOENT;
}
if (sub->node_id == BT_MESH_NODE_IDENTITY_RUNNING) {
u32_t active = k_uptime_get_32() - sub->node_id_start;
uint32_t active = k_uptime_get_32() - sub->node_id_start;
if (active < NODE_ID_TIMEOUT) {
remaining = NODE_ID_TIMEOUT - active;
@@ -1233,7 +1271,7 @@ static s32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
subnet_count = sub_count();
BT_DBG("sub_count %u", subnet_count);
if (subnet_count > 1) {
s32_t max_timeout;
int32_t max_timeout;
/* We use NODE_ID_TIMEOUT as a starting point since it may
* be less than 60 seconds. Divide this period into at least
@@ -1251,6 +1289,8 @@ static s32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
BT_DBG("Advertising %d ms for net_idx 0x%04x",
(int) remaining, sub->net_idx);
beacon_sub = bt_mesh_subnet_next(beacon_sub);
return remaining;
}
#endif /* GATT_PROXY */
@@ -1301,7 +1341,7 @@ static size_t gatt_prov_adv_create(struct bt_data prov_sd[2])
}
#endif /* PB_GATT */
s32_t bt_mesh_proxy_adv_start(void)
int32_t bt_mesh_proxy_adv_start(void)
{
BT_DBG("");
@@ -1363,6 +1403,19 @@ void bt_mesh_proxy_adv_stop(void)
}
}
#if defined(CONFIG_BT_MESH_GATT_PROXY)
static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
{
if (evt == BT_MESH_KEY_DELETED) {
if (sub == beacon_sub) {
beacon_sub = NULL;
}
} else {
bt_mesh_proxy_beacon_send(sub);
}
}
#endif
static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg)
{
#if MYNEWT_VAL(BLE_EXT_ADV)
@@ -1479,6 +1532,12 @@ int bt_mesh_proxy_init(void)
{
int i;
#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
if (!bt_mesh_subnet_cb_list[4]) {
bt_mesh_subnet_cb_list[4] = subnet_evt;
}
#endif
for (i = 0; i < MYNEWT_VAL(BLE_MAX_CONNECTIONS); ++i) {
#if (MYNEWT_VAL(BLE_MESH_GATT_PROXY))
k_work_init(&clients[i].send_beacons, proxy_send_beacons);
@@ -1498,5 +1557,15 @@ int bt_mesh_proxy_init(void)
return 0;
}
void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb)
{
if (!atomic_get(&pending_notifications)) {
cb->cb();
return;
}
sys_slist_append(&idle_waiters, &cb->n);
}
#endif /* MYNEWT_VAL(BLE_MESH_PROXY) */
#endif

View File

@@ -15,8 +15,14 @@
#define BT_MESH_PROXY_PROV 0x03
#include "../include/mesh/mesh.h"
#include "../include/mesh/slist.h"
int bt_mesh_proxy_send(uint16_t conn_handle, u8_t type, struct os_mbuf *msg);
struct bt_mesh_proxy_idle_cb {
sys_snode_t n;
void (*cb)(void);
};
int bt_mesh_proxy_send(uint16_t conn_handle, uint8_t type, struct os_mbuf *msg);
int bt_mesh_proxy_prov_enable(void);
int bt_mesh_proxy_prov_disable(bool disconnect);
@@ -29,16 +35,17 @@ 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);
int32_t bt_mesh_proxy_adv_start(void);
void bt_mesh_proxy_adv_stop(void);
void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub);
void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub);
bool bt_mesh_proxy_relay(struct os_mbuf *buf, u16_t dst);
void bt_mesh_proxy_addr_add(struct os_mbuf *buf, u16_t addr);
bool bt_mesh_proxy_relay(struct os_mbuf *buf, uint16_t dst);
void bt_mesh_proxy_addr_add(struct os_mbuf *buf, uint16_t addr);
int bt_mesh_proxy_init(void);
void bt_mesh_proxy_on_idle(struct bt_mesh_proxy_idle_cb *cb);
int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg);

View File

@@ -0,0 +1,167 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2020 Lingao Meng
*
* SPDX-License-Identifier: Apache-2.0
*/
#define MESH_LOG_MODULE BLE_MESH_RPL_LOG
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#if MYNEWT_VAL(BLE_MESH)
#include "nimble/porting/nimble/include/log/log.h"
#include "mesh_priv.h"
#include "adv.h"
#include "net.h"
#include "rpl.h"
#include "settings.h"
static struct bt_mesh_rpl replay_list[MYNEWT_VAL(BLE_MESH_CRPL)];
void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
struct bt_mesh_net_rx *rx)
{
rpl->src = rx->ctx.addr;
rpl->seq = rx->seq;
rpl->old_iv = rx->old_iv;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_rpl(rpl);
}
}
/* Check the Replay Protection List for a replay attempt. If non-NULL match
* parameter is given the RPL slot is returned but it is not immediately
* updated (needed for segmented messages), whereas if a NULL match is given
* the RPL is immediately updated (used for unsegmented messages).
*/
bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx,
struct bt_mesh_rpl **match)
{
int i;
/* Don't bother checking messages from ourselves */
if (rx->net_if == BT_MESH_NET_IF_LOCAL) {
return false;
}
/* The RPL is used only for the local node */
if (!rx->local_match) {
return false;
}
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
struct bt_mesh_rpl *rpl = &replay_list[i];
/* Empty slot */
if (!rpl->src) {
if (match) {
*match = rpl;
} else {
bt_mesh_rpl_update(rpl, rx);
}
return false;
}
/* Existing slot for given address */
if (rpl->src == rx->ctx.addr) {
if (rx->old_iv && !rpl->old_iv) {
return true;
}
if ((!rx->old_iv && rpl->old_iv) ||
rpl->seq < rx->seq) {
if (match) {
*match = rpl;
} else {
bt_mesh_rpl_update(rpl, rx);
}
return false;
} else {
return true;
}
}
}
BT_ERR("RPL is full!");
return true;
}
void bt_mesh_rpl_clear(void)
{
BT_DBG("");
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_clear_rpl();
} else {
(void)memset(replay_list, 0, sizeof(replay_list));
}
}
struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src)
{
int i;
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
if (replay_list[i].src == src) {
return &replay_list[i];
}
}
return NULL;
}
struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src)
{
int i;
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
if (!replay_list[i].src) {
replay_list[i].src = src;
return &replay_list[i];
}
}
return NULL;
}
void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data)
{
int i;
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
func(&replay_list[i], user_data);
}
}
void bt_mesh_rpl_reset(void)
{
int i;
/* Discard "old old" IV Index entries from RPL and flag
* any other ones (which are valid) as old.
*/
for (i = 0; i < ARRAY_SIZE(replay_list); i++) {
struct bt_mesh_rpl *rpl = &replay_list[i];
if (rpl->src) {
if (rpl->old_iv) {
(void)memset(rpl, 0, sizeof(*rpl));
} else {
rpl->old_iv = true;
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_rpl(rpl);
}
}
}
}
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,30 @@
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2020 Lingao Meng
*
* SPDX-License-Identifier: Apache-2.0
*/
struct bt_mesh_rpl {
uint16_t src;
bool old_iv;
#if defined(CONFIG_BT_SETTINGS)
bool store;
#endif
uint32_t seq;
};
typedef void (*bt_mesh_rpl_func_t)(struct bt_mesh_rpl *rpl,
void *user_data);
void bt_mesh_rpl_reset(void);
bool bt_mesh_rpl_check(struct bt_mesh_net_rx *rx,
struct bt_mesh_rpl **match);
void bt_mesh_rpl_clear(void);
struct bt_mesh_rpl *bt_mesh_rpl_find(uint16_t src);
struct bt_mesh_rpl *bt_mesh_rpl_alloc(uint16_t src);
void bt_mesh_rpl_foreach(bt_mesh_rpl_func_t func, void *user_data);
void bt_mesh_rpl_update(struct bt_mesh_rpl *rpl,
struct bt_mesh_net_rx *rx);

File diff suppressed because it is too large Load Diff

View File

@@ -8,20 +8,25 @@ void bt_mesh_store_net(void);
void bt_mesh_store_iv(bool only_duration);
void bt_mesh_store_seq(void);
void bt_mesh_store_rpl(struct bt_mesh_rpl *rpl);
void bt_mesh_store_subnet(struct bt_mesh_subnet *sub);
void bt_mesh_store_app_key(struct bt_mesh_app_key *key);
void bt_mesh_store_subnet(uint16_t net_idx);
void bt_mesh_store_app_key(uint16_t app_idx);
void bt_mesh_store_hb_pub(void);
void bt_mesh_store_cfg(void);
void bt_mesh_store_mod_bind(struct bt_mesh_model *mod);
void bt_mesh_store_mod_sub(struct bt_mesh_model *mod);
void bt_mesh_store_mod_pub(struct bt_mesh_model *mod);
void bt_mesh_store_label(void);
void bt_mesh_store_node(struct bt_mesh_node *node);
void bt_mesh_store_cdb(void);
void bt_mesh_store_cdb_node(const struct bt_mesh_cdb_node *node);
void bt_mesh_store_cdb_subnet(const struct bt_mesh_cdb_subnet *sub);
void bt_mesh_store_cdb_app_key(const struct bt_mesh_cdb_app_key *app);
void bt_mesh_clear_net(void);
void bt_mesh_clear_subnet(struct bt_mesh_subnet *sub);
void bt_mesh_clear_app_key(struct bt_mesh_app_key *key);
void bt_mesh_clear_subnet(uint16_t net_idx);
void bt_mesh_clear_app_key(uint16_t app_idx);
void bt_mesh_clear_rpl(void);
void bt_mesh_clear_node(struct bt_mesh_node *node);
void bt_mesh_clear_cdb_node(struct bt_mesh_cdb_node *node);
void bt_mesh_clear_cdb_subnet(struct bt_mesh_cdb_subnet *sub);
void bt_mesh_clear_cdb_app_key(struct bt_mesh_cdb_app_key *app);
void bt_mesh_settings_init(void);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,670 @@
/*
* Copyright (c) 2017 Intel Corporation
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "nimble/porting/nimble/include/syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_NET_KEYS_LOG
#if MYNEWT_VAL(BLE_MESH)
#include "nimble/porting/nimble/include/log/log.h"
#include "crypto.h"
#include "adv.h"
#include "../include/mesh/mesh.h"
#include "net.h"
#include "mesh_priv.h"
#include "lpn.h"
#include "friend.h"
#include "proxy.h"
#include "transport.h"
#include "access.h"
#include "foundation.h"
#include "beacon.h"
#include "rpl.h"
#include "settings.h"
#include "prov.h"
#ifdef CONFIG_BT_MESH_GATT_PROXY
void (*bt_mesh_subnet_cb_list[5]) (struct bt_mesh_subnet *sub,
enum bt_mesh_key_evt evt);
#else
void (*bt_mesh_subnet_cb_list[4]) (struct bt_mesh_subnet *sub,
enum bt_mesh_key_evt evt);
#endif
static struct bt_mesh_subnet subnets[CONFIG_BT_MESH_SUBNET_COUNT] = {
[0 ... (CONFIG_BT_MESH_SUBNET_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
},
};
static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
{
int i;
for (i = 0; i < (sizeof(bt_mesh_subnet_cb_list)/sizeof(void *)); i++) {
BT_DBG("%d", i);
if (bt_mesh_subnet_cb_list[i]) {
bt_mesh_subnet_cb_list[i] (sub, evt);
}
}
}
uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub)
{
uint8_t flags = 0x00;
if (sub && (sub->kr_phase == BT_MESH_KR_PHASE_2)) {
flags |= BT_MESH_NET_FLAG_KR;
}
if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS)) {
flags |= BT_MESH_NET_FLAG_IVU;
}
return flags;
}
static void key_refresh(struct bt_mesh_subnet *sub, uint8_t new_phase)
{
BT_DBG("Phase 0x%02x -> 0x%02x", sub->kr_phase, new_phase);
switch (new_phase) {
/* Added second set of keys */
case BT_MESH_KR_PHASE_1:
sub->kr_phase = new_phase;
subnet_evt(sub, BT_MESH_KEY_UPDATED);
break;
/* Now using new keys for TX */
case BT_MESH_KR_PHASE_2:
sub->kr_phase = new_phase;
subnet_evt(sub, BT_MESH_KEY_SWAPPED);
break;
/* Revoking keys */
case BT_MESH_KR_PHASE_3:
if (sub->kr_phase == BT_MESH_KR_NORMAL) {
return;
}
/* __fallthrough; */
case BT_MESH_KR_NORMAL:
sub->kr_phase = BT_MESH_KR_NORMAL;
memcpy(&sub->keys[0], &sub->keys[1], sizeof(sub->keys[0]));
sub->keys[1].valid = 0U;
subnet_evt(sub, BT_MESH_KEY_REVOKED);
break;
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
BT_DBG("Storing Updated NetKey persistently");
bt_mesh_store_subnet(sub->net_idx);
}
}
void bt_mesh_kr_update(struct bt_mesh_subnet *sub, bool kr_flag, bool new_key)
{
if (!new_key) {
return;
}
if (sub->kr_phase == BT_MESH_KR_PHASE_1) {
/* Bluetooth Mesh Profile Specification Section 3.10.4.1:
* Can skip phase 2 if we get KR=0 on new key.
*/
key_refresh(sub, (kr_flag ? BT_MESH_KR_PHASE_2 :
BT_MESH_KR_PHASE_3));
} else if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !kr_flag) {
key_refresh(sub, BT_MESH_KR_PHASE_3);
}
}
static struct bt_mesh_subnet *subnet_alloc(uint16_t net_idx)
{
struct bt_mesh_subnet *sub = NULL;
for (int i = 0; i < ARRAY_SIZE(subnets); i++) {
/* Check for already existing subnet */
if (subnets[i].net_idx == net_idx) {
return &subnets[i];
}
if (!sub && subnets[i].net_idx == BT_MESH_KEY_UNUSED) {
sub = &subnets[i];
}
}
return sub;
}
static void subnet_del(struct bt_mesh_subnet *sub)
{
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_clear_subnet(sub->net_idx);
}
bt_mesh_net_loopback_clear(sub->net_idx);
subnet_evt(sub, BT_MESH_KEY_DELETED);
(void)memset(sub, 0, sizeof(*sub));
sub->net_idx = BT_MESH_KEY_UNUSED;
}
static int msg_cred_create(struct bt_mesh_net_cred *cred, const uint8_t *p,
size_t p_len, const uint8_t key[16])
{
return bt_mesh_k2(key, p, p_len, &cred->nid, cred->enc, cred->privacy);
}
static int net_keys_create(struct bt_mesh_subnet_keys *keys,
const uint8_t key[16])
{
uint8_t p = 0;
int err;
err = msg_cred_create(&keys->msg, &p, 1, key);
if (err) {
BT_ERR("Unable to generate NID, EncKey & PrivacyKey");
return err;
}
memcpy(keys->net, key, 16);
BT_DBG("NID 0x%02x EncKey %s", keys->msg.nid,
bt_hex(keys->msg.enc, 16));
BT_DBG("PrivacyKey %s", bt_hex(keys->msg.privacy, 16));
err = bt_mesh_k3(key, keys->net_id);
if (err) {
BT_ERR("Unable to generate Net ID");
return err;
}
BT_DBG("NetID %s", bt_hex(keys->net_id, 8));
#if defined(CONFIG_BT_MESH_GATT_PROXY)
err = bt_mesh_identity_key(key, keys->identity);
if (err) {
BT_ERR("Unable to generate IdentityKey");
return err;
}
BT_DBG("IdentityKey %s", bt_hex(keys->identity, 16));
#endif /* GATT_PROXY */
err = bt_mesh_beacon_key(key, keys->beacon);
if (err) {
BT_ERR("Unable to generate beacon key");
return err;
}
BT_DBG("BeaconKey %s", bt_hex(keys->beacon, 16));
keys->valid = 1U;
return 0;
}
uint8_t bt_mesh_subnet_add(uint16_t net_idx, const uint8_t key[16])
{
struct bt_mesh_subnet *sub = NULL;
int err;
BT_DBG("0x%03x", net_idx);
sub = subnet_alloc(net_idx);
if (!sub) {
return STATUS_INSUFF_RESOURCES;
}
if (sub->net_idx == net_idx) {
if (memcmp(key, sub->keys[0].net, 16)) {
return STATUS_IDX_ALREADY_STORED;
}
return STATUS_SUCCESS;
}
err = net_keys_create(&sub->keys[0], key);
if (err) {
return STATUS_UNSPECIFIED;
}
sub->net_idx = net_idx;
sub->kr_phase = BT_MESH_KR_NORMAL;
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
} else {
sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED;
}
subnet_evt(sub, BT_MESH_KEY_ADDED);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
BT_DBG("Storing NetKey persistently");
bt_mesh_store_subnet(sub->net_idx);
}
return STATUS_SUCCESS;
}
bool bt_mesh_subnet_exists(uint16_t net_idx)
{
return !!bt_mesh_subnet_get(net_idx);
}
uint8_t bt_mesh_subnet_update(uint16_t net_idx, const uint8_t key[16])
{
struct bt_mesh_subnet *sub;
int err;
BT_DBG("0x%03x", net_idx);
sub = bt_mesh_subnet_get(net_idx);
if (!sub) {
return STATUS_INVALID_NETKEY;
}
/* The node shall successfully process a NetKey Update message on a
* valid NetKeyIndex when the NetKey value is different and the Key
* Refresh procedure has not been started, or when the NetKey value is
* the same in Phase 1. The NetKey Update message shall generate an
* error when the node is in Phase 2, or Phase 3.
*/
switch (sub->kr_phase) {
case BT_MESH_KR_NORMAL:
if (!memcmp(key, sub->keys[0].net, 16)) {
return STATUS_IDX_ALREADY_STORED;
}
break;
case BT_MESH_KR_PHASE_1:
if (!memcmp(key, sub->keys[1].net, 16)) {
return STATUS_SUCCESS;
}
/* __fallthrough; */
case BT_MESH_KR_PHASE_2:
case BT_MESH_KR_PHASE_3:
return STATUS_CANNOT_UPDATE;
}
err = net_keys_create(&sub->keys[1], key);
if (err) {
return STATUS_CANNOT_UPDATE;
}
key_refresh(sub, BT_MESH_KR_PHASE_1);
return STATUS_SUCCESS;
}
uint8_t bt_mesh_subnet_del(uint16_t net_idx)
{
struct bt_mesh_subnet *sub;
BT_DBG("0x%03x", net_idx);
sub = bt_mesh_subnet_get(net_idx);
if (!sub) {
/* This could be a retry of a previous attempt that had its
* response lost, so pretend that it was a success.
*/
return STATUS_INVALID_NETKEY;
}
subnet_del(sub);
return STATUS_SUCCESS;
}
int bt_mesh_friend_cred_create(struct bt_mesh_net_cred *cred, uint16_t lpn_addr,
uint16_t frnd_addr, uint16_t lpn_counter,
uint16_t frnd_counter, const uint8_t key[16])
{
uint8_t p[9];
p[0] = 0x01;
sys_put_be16(lpn_addr, p + 1);
sys_put_be16(frnd_addr, p + 3);
sys_put_be16(lpn_counter, p + 5);
sys_put_be16(frnd_counter, p + 7);
return msg_cred_create(cred, p, sizeof(p), key);
}
uint8_t bt_mesh_subnet_kr_phase_set(uint16_t net_idx, uint8_t *phase)
{
/* Table in Bluetooth Mesh Profile Specification Section 4.2.14: */
const uint8_t valid_transitions[] = {
BIT(BT_MESH_KR_PHASE_3), /* Normal phase: KR is started by key update */
BIT(BT_MESH_KR_PHASE_2) | BIT(BT_MESH_KR_PHASE_3), /* Phase 1 */
BIT(BT_MESH_KR_PHASE_3), /* Phase 2 */
/* Subnet is never in Phase 3 */
};
struct bt_mesh_subnet *sub;
BT_DBG("0x%03x", net_idx);
sub = bt_mesh_subnet_get(net_idx);
if (!sub) {
*phase = 0x00;
return STATUS_INVALID_NETKEY;
}
if (*phase == sub->kr_phase) {
return STATUS_SUCCESS;
}
if (sub->kr_phase < ARRAY_SIZE(valid_transitions) &&
valid_transitions[sub->kr_phase] & BIT(*phase)) {
key_refresh(sub, *phase);
*phase = sub->kr_phase;
return STATUS_SUCCESS;
}
BT_WARN("Invalid KR transition: 0x%02x -> 0x%02x", sub->kr_phase,
*phase);
*phase = sub->kr_phase;
return STATUS_CANNOT_UPDATE;
}
uint8_t bt_mesh_subnet_kr_phase_get(uint16_t net_idx, uint8_t *phase)
{
struct bt_mesh_subnet *sub;
sub = bt_mesh_subnet_get(net_idx);
if (!sub) {
*phase = BT_MESH_KR_NORMAL;
return STATUS_INVALID_NETKEY;
}
*phase = sub->kr_phase;
return STATUS_SUCCESS;
}
uint8_t bt_mesh_subnet_node_id_set(uint16_t net_idx,
enum bt_mesh_feat_state node_id)
{
struct bt_mesh_subnet *sub;
if (node_id == BT_MESH_FEATURE_NOT_SUPPORTED) {
return STATUS_CANNOT_SET;
}
sub = bt_mesh_subnet_get(net_idx);
if (!sub) {
return STATUS_INVALID_NETKEY;
}
if (!IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
return STATUS_FEAT_NOT_SUPP;
}
if (node_id) {
bt_mesh_proxy_identity_start(sub);
} else {
bt_mesh_proxy_identity_stop(sub);
}
bt_mesh_adv_update();
return STATUS_SUCCESS;
}
uint8_t bt_mesh_subnet_node_id_get(uint16_t net_idx,
enum bt_mesh_feat_state *node_id)
{
struct bt_mesh_subnet *sub;
sub = bt_mesh_subnet_get(net_idx);
if (!sub) {
*node_id = 0x00;
return STATUS_INVALID_NETKEY;
}
*node_id = sub->node_id;
return STATUS_SUCCESS;
}
ssize_t bt_mesh_subnets_get(uint16_t net_idxs[], size_t max, off_t skip)
{
size_t count = 0;
for (int i = 0; i < ARRAY_SIZE(subnets); i++) {
struct bt_mesh_subnet *sub = &subnets[i];
if (sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (skip) {
skip--;
continue;
}
if (count >= max) {
return -ENOMEM;
}
net_idxs[count++] = sub->net_idx;
}
return count;
}
struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx)
{
for (int i = 0; i < ARRAY_SIZE(subnets); i++) {
struct bt_mesh_subnet *sub = &subnets[i];
if (sub->net_idx == net_idx) {
return sub;
}
}
return NULL;
}
int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase,
const uint8_t old_key[16], const uint8_t new_key[16])
{
const uint8_t *keys[] = { old_key, new_key };
struct bt_mesh_subnet *sub;
sub = subnet_alloc(net_idx);
if (!sub) {
return -ENOMEM;
}
if (sub->net_idx == net_idx) {
return -EALREADY;
}
for (int i = 0; i < ARRAY_SIZE(keys); i++) {
if (!keys[i]) {
continue;
}
if (net_keys_create(&sub->keys[i], keys[i])) {
return -EIO;
}
}
sub->net_idx = net_idx;
sub->kr_phase = kr_phase;
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
sub->node_id = BT_MESH_NODE_IDENTITY_STOPPED;
} else {
sub->node_id = BT_MESH_NODE_IDENTITY_NOT_SUPPORTED;
}
/* Make sure we have valid beacon data to be sent */
bt_mesh_beacon_update(sub);
return 0;
}
struct bt_mesh_subnet *bt_mesh_subnet_find(int (*cb)(struct bt_mesh_subnet *sub,
void *cb_data),
void *cb_data)
{
for (int i = 0; i < ARRAY_SIZE(subnets); i++) {
if (subnets[i].net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
if (!cb || cb(&subnets[i], cb_data)) {
return &subnets[i];
}
}
return NULL;
}
size_t bt_mesh_subnet_foreach(void (*cb)(struct bt_mesh_subnet *sub))
{
size_t count = 0;
for (int i = 0; i < ARRAY_SIZE(subnets); i++) {
if (subnets[i].net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
cb(&subnets[i]);
count++;
}
return count;
}
struct bt_mesh_subnet *bt_mesh_subnet_next(struct bt_mesh_subnet *sub)
{
if (sub) {
sub++;
} else {
sub = &subnets[0];
}
for (int i = 0; i < ARRAY_SIZE(subnets); i++, sub++) {
/* Roll over once we reach the end */
if (sub == &subnets[ARRAY_SIZE(subnets)]) {
sub = &subnets[0];
}
if (sub->net_idx != BT_MESH_KEY_UNUSED) {
return sub;
}
}
return NULL;
}
void bt_mesh_net_keys_reset(void)
{
int i;
/* Delete all net keys, which also takes care of all app keys which
* are associated with each net key.
*/
for (i = 0; i < ARRAY_SIZE(subnets); i++) {
struct bt_mesh_subnet *sub = &subnets[i];
if (sub->net_idx != BT_MESH_KEY_UNUSED) {
subnet_del(sub);
}
}
}
bool bt_mesh_net_cred_find(struct bt_mesh_net_rx *rx, struct os_mbuf *in,
struct os_mbuf *out,
bool (*cb)(struct bt_mesh_net_rx *rx,
struct os_mbuf *in,
struct os_mbuf *out,
const struct bt_mesh_net_cred *cred))
{
int i, j;
BT_DBG("");
#if MYNEWT_VAL(BLE_MESH_LOW_POWER)
if (bt_mesh_lpn_waiting_update()) {
rx->sub = bt_mesh.lpn.sub;
for (j = 0; j < ARRAY_SIZE(bt_mesh.lpn.cred); j++) {
if (!rx->sub->keys[j].valid) {
continue;
}
if (cb(rx, in, out, &bt_mesh.lpn.cred[j])) {
rx->new_key = (j > 0);
rx->friend_cred = 1U;
rx->ctx.net_idx = rx->sub->net_idx;
return true;
}
}
/* LPN Should only receive on the friendship credentials when in
* a friendship.
*/
return false;
}
#endif
#if MYNEWT_VAL(BLE_MESH_FRIEND)
/** Each friendship has unique friendship credentials */
for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
if (!frnd->subnet) {
continue;
}
rx->sub = frnd->subnet;
for (j = 0; j < ARRAY_SIZE(frnd->cred); j++) {
if (!rx->sub->keys[j].valid) {
continue;
}
if (cb(rx, in, out, &frnd->cred[j])) {
rx->new_key = (j > 0);
rx->friend_cred = 1U;
rx->ctx.net_idx = rx->sub->net_idx;
return true;
}
}
}
#endif
for (i = 0; i < ARRAY_SIZE(subnets); i++) {
rx->sub = &subnets[i];
if (rx->sub->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
for (j = 0; j < ARRAY_SIZE(rx->sub->keys); j++) {
if (!rx->sub->keys[j].valid) {
continue;
}
if (cb(rx, in, out, &rx->sub->keys[j].msg)) {
rx->new_key = (j > 0);
rx->friend_cred = 0U;
rx->ctx.net_idx = rx->sub->net_idx;
return true;
}
}
}
return false;
}
#endif /* MYNEWT_VAL(BLE_MESH) */

View File

@@ -0,0 +1,197 @@
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _BLUETOOTH_MESH_SUBNET_H_
#define _BLUETOOTH_MESH_SUBNET_H_
#include <stdint.h>
#include <sys/types.h>
#include "../include/mesh/glue.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
/** Which of the two subnet.keys should be used for sending. */
#define SUBNET_KEY_TX_IDX(sub) ((sub)->kr_phase == BT_MESH_KR_PHASE_2)
struct bt_mesh_net_rx;
enum bt_mesh_key_evt;
/** Network message encryption credentials */
struct bt_mesh_net_cred {
uint8_t nid; /* NID */
uint8_t enc[16]; /* EncKey */
uint8_t privacy[16]; /* PrivacyKey */
};
/** Subnet instance. */
struct bt_mesh_subnet {
uint32_t beacon_sent; /* Timestamp of last sent beacon */
uint8_t beacons_last; /* Number of beacons during last
* observation window
*/
uint8_t beacons_cur; /* Number of beaconds observed during
* currently ongoing window.
*/
uint8_t beacon_cache[21]; /* Cached last authenticated beacon */
uint16_t net_idx; /* NetKeyIndex */
uint8_t kr_phase; /* Key Refresh Phase */
uint8_t node_id; /* Node Identity State */
uint32_t node_id_start; /* Node Identity started timestamp */
uint8_t auth[8]; /* Beacon Authentication Value */
struct bt_mesh_subnet_keys {
bool valid;
uint8_t net[16]; /* NetKey */
struct bt_mesh_net_cred msg;
uint8_t net_id[8]; /* Network ID */
#if defined(CONFIG_BT_MESH_GATT_PROXY)
uint8_t identity[16]; /* IdentityKey */
#endif
uint8_t beacon[16]; /* BeaconKey */
} keys[2];
};
#ifdef CONFIG_BT_MESH_GATT_PROXY
extern void (*bt_mesh_subnet_cb_list[5]) (struct bt_mesh_subnet *sub,
enum bt_mesh_key_evt evt);
#else
extern void (*bt_mesh_subnet_cb_list[4]) (struct bt_mesh_subnet *sub,
enum bt_mesh_key_evt evt);
#endif
/** Subnet callback structure. Instantiate with @ref BT_MESH_SUBNET_CB */
struct bt_mesh_subnet_cb {
void (*evt_handler)(struct bt_mesh_subnet *subnet,
enum bt_mesh_key_evt evt);
};
/** @brief Reset all Network keys. */
void bt_mesh_net_keys_reset(void);
/** @brief Call cb on every valid Subnet until it returns a non-zero value.
*
* @param cb Callback to call, or NULL to return first valid subnet.
* @param cb_data Callback data to pass to callback.
*
* @return Subnet that returned non-zero value.
*/
struct bt_mesh_subnet *bt_mesh_subnet_find(int (*cb)(struct bt_mesh_subnet *sub,
void *cb_data),
void *cb_data);
/** @brief Iterate through all valid Subnets.
*
* @param cb Callback to call on every Subnet.
*
* @returns The number of valid subnets.
*/
size_t bt_mesh_subnet_foreach(void (*cb)(struct bt_mesh_subnet *sub));
/** @brief Get the next valid Subnet.
*
* If there's only one valid Subnet, this will be returned on every call.
*
* @param sub Previous Subnet, or NULL to get the first valid.
*
* @returns Gets the next valid Subnet after @c sub, or NULL if there are no
* valid Subnets.
*/
struct bt_mesh_subnet *bt_mesh_subnet_next(struct bt_mesh_subnet *sub);
/** @brief Get a pointer to the Subnet with the given index.
*
* @param net_idx Network index to look for.
*
* @returns Subnet with index @c net_idx, or NULL if no such Subnet is known.
*/
struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx);
/** @brief Initialize a new Subnet.
*
* @param net_idx Network index of the Subnet.
* @param kr_phase Key refresh phase the Subnet should be in.
* @param key The current network key for the Subnet.
* @param new_key New network key, if available.
*
* @returns 0 on success, or (negative) error code on failure.
*/
int bt_mesh_subnet_set(uint16_t net_idx, uint8_t kr_phase,
const uint8_t key[16], const uint8_t new_key[16]);
/** @brief Create Friendship credentials.
*
* @param cred Credential object to create.
* @param lpn_addr Address of the LPN node in the friendship.
* @param frnd_addr Address of the Friend node in the friendship.
* @param lpn_counter The LPN's counter parameter.
* @param frnd_counter The Friend node's counter parameter.
* @param key Network key to create the Friendship credentials for.
*
* @returns 0 on success, or (negative) error code on failure.
*/
int bt_mesh_friend_cred_create(struct bt_mesh_net_cred *cred,
uint16_t lpn_addr, uint16_t frnd_addr,
uint16_t lpn_counter, uint16_t frnd_counter,
const uint8_t key[16]);
/** @brief Iterate through all valid network credentials to decrypt a message.
*
* @param rx Network RX parameters, passed to the callback.
* @param in Input message buffer, passed to the callback.
* @param out Output message buffer, passed to the callback.
* @param cb Callback to call for each known network credential. Iteration
* stops when this callback returns @c true.
*
* @returns Whether any of the credentials got a @c true return from the
* callback.
*/
bool bt_mesh_net_cred_find(struct bt_mesh_net_rx *rx, struct os_mbuf *in,
struct os_mbuf *out,
bool (*cb)(struct bt_mesh_net_rx *rx,
struct os_mbuf *in,
struct os_mbuf *out,
const struct bt_mesh_net_cred *cred));
/** @brief Get the network flags of the given Subnet.
*
* @param sub Subnet to get the network flags of.
*
* @returns A bitmap of @ref BT_MESH_NET_FLAG_KR and @ref BT_MESH_NET_FLAG_IVU.
*/
uint8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub);
/** @brief Process a Key Refresh event from a beacon.
*
* @param sub Subnet the Key Refresh was received on.
* @param kr_flag Key Refresh flag.
* @param new_key Whether the Key Refresh event was received on the new key
* set.
*/
void bt_mesh_kr_update(struct bt_mesh_subnet *sub, bool kr_flag, bool new_key);
/** @brief Check whether the Subnet has the refreshed keys.
*
* @param sub Subnet.
*
* @returns Whether the Subnet's second key is valid.
*/
static inline bool
bt_mesh_subnet_has_new_key(const struct bt_mesh_subnet *sub)
{
return sub->kr_phase != BT_MESH_KR_NORMAL;
}
#endif /* _BLUETOOTH_MESH_SUBNET_H_ */

Some files were not shown because too many files have changed in this diff Show More