Merge pull request #12942 from Jason2866/C3_BLE

BLE support for ESP32-C3
This commit is contained in:
Theo Arends 2021-08-24 08:36:11 +02:00 committed by GitHub
commit 308e4a536d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
164 changed files with 10846 additions and 8809 deletions

View File

@ -4,6 +4,7 @@
"ldscript": "esp32c3_out.ld"
},
"core": "esp32",
"extra_flags": "-DBOARD_HAS_PSRAM",
"f_cpu": "160000000L",
"f_flash": "80000000L",
"flash_mode": "dout",

View File

@ -4,6 +4,7 @@
"ldscript": "esp32s2_out.ld"
},
"core": "esp32",
"extra_flags": "-DBOARD_HAS_PSRAM",
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dout",

View File

@ -20,12 +20,12 @@
/*
* Xtensa toolchain declares `int32_t` as `int` but RISC-V toolchain
* declares `int32_t` as `long int` which causes compilation errors.
*
*
* See:
* https://github.com/espressif/esp-idf/issues/6906
* https://github.com/espressif/arduino-esp32/issues/5086
*
* You need to add the following lines in `build_flags`:
*
* You need to add the following lines in `build_flags`:
* -I$PROJECT_DIR/include
* -include "esp32x_fixes.h"
*/
@ -39,16 +39,27 @@
#endif // __riscv
#if CONFIG_IDF_TARGET_ESP32C3
// fix a bug in esp-idf 4.4 for esp32c3
#ifndef REG_SPI_BASE
#define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
#endif
//alias, deprecated for the chips after esp32s2
#ifdef CONFIG_IDF_TARGET_ESP32
#define SPI_HOST SPI1_HOST
#define HSPI_HOST SPI2_HOST
#define VSPI_HOST SPI3_HOST
// SPI_MOSI_DLEN_REG is not defined anymore in esp32c3, instead use SPI_MS_DLEN_REG
#define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x)
//alias for different chips, deprecated for the chips after esp32s2
#elif CONFIG_IDF_TARGET_ESP32S2
// SPI_HOST (SPI1_HOST) is not supported by the SPI Master and SPI Slave driver on ESP32-S2 and later
#define SPI_HOST SPI1_HOST
#define FSPI_HOST SPI2_HOST
#define HSPI_HOST SPI3_HOST
#define VSPI_HOST SPI3_HOST
#elif CONFIG_IDF_TARGET_ESP32C3
#define SPI_HOST SPI1_HOST
#define HSPI_HOST SPI2_HOST
#define VSPI_HOST SPI2_HOST /* No SPI3_host on C3 */
#endif
// fix a bug in esp-idf 4.4 for esp32c3
#ifndef REG_SPI_BASE
#define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
// SPI_MOSI_DLEN_REG is not defined anymore in esp32c3, instead use SPI_MS_DLEN_REG
#define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x)
#endif // REG_SPI_BASE
#endif // TARGET

View File

@ -2,6 +2,52 @@
All notable changes to this project will be documented in this file.
## [1.3.1] - 2021-08-04
### Fixed
- Corrected a compiler/linker error when an application or a library uses bluetooth classic due to the redefinition of `btInUse`.
## [1.3.0] - 2021-08-02
### Added
- `NimBLECharacteristic::removeDescriptor`: Dynamically remove a descriptor from a characterisic. Takes effect after all connections are closed and sends a service changed indication.
- `NimBLEService::removeCharacteristic`: Dynamically remove a characteristic from a service. Takes effect after all connections are closed and sends a service changed indication
- `NimBLEServerCallbacks::onMTUChange`: This is callback is called when the MTU is updated after connection with a client.
- ESP32C3 support
- Whitelist API:
- `NimBLEDevice::whiteListAdd`: Add a device to the whitelist.
- `NimBLEDevice::whiteListRemove`: Remove a device from the whitelist.
- `NimBLEDevice::onWhiteList`: Check if the device is on the whitelist.
- `NimBLEDevice::getWhiteListCount`: Gets the size of the whitelist
- `NimBLEDevice::getWhiteListAddress`: Get the address of a device on the whitelist by index value.
- Bond management API:
- `NimBLEDevice::getNumBonds`: Gets the number of bonds stored.
- `NimBLEDevice::isBonded`: Checks if the device is bonded.
- `NimBLEDevice::deleteAllBonds`: Deletes all bonds.
- `NimBLEDevice::getBondedAddress`: Gets the address of a bonded device by the index value.
- `NimBLECharacteristic::getCallbacks` to retrieve the current callback handler.
- Connection Information class: `NimBLEConnInfo`.
- `NimBLEScan::clearDuplicateCache`: This can be used to reset the cache of advertised devices so they will be immediately discovered again.
### Changed
- FreeRTOS files have been removed as they are not used by the library.
- Services, characteristics and descriptors can now be created statically and added after.
- Excess logging and some asserts removed.
- Use ESP_LOGx macros to enable using local log level filtering.
### Fixed
- `NimBLECharacteristicCallbacks::onSubscribe` Is now called after the connection is added to the vector.
- Corrected bonding failure when reinitializing the BLE stack.
- Writing to a characterisic with a std::string value now correctly writes values with null characters.
- Retrieving remote descriptors now uses the characterisic end handle correctly.
- Missing data in long writes to remote descriptors.
- Hanging on task notification when sending an indication from the characteristic callback.
- BLE controller memory could be released when using Arduino as a component.
- Complile errors with NimBLE release 1.3.0.
## [1.2.0] - 2021-02-08
### Added

View File

@ -72,9 +72,9 @@ such as increasing max connections, default is 3, absolute maximum connections i
<br/>
# Development Status
This Library is tracking the esp-nimble repo, nimble-1.2.0-idf master branch, currently [@f4ae049.](https://github.com/espressif/esp-nimble)
This Library is tracking the esp-nimble repo, nimble-1.3.0-idf master branch, currently [@5bb7b40.](https://github.com/espressif/esp-nimble)
Also tracking the NimBLE related changes in ESP-IDF, master branch, currently [@3caa969.](https://github.com/espressif/esp-idf/tree/master/components/bt/host/nimble)
Also tracking the NimBLE related changes in ESP-IDF, master branch, currently [@639e7ad.](https://github.com/espressif/esp-idf/tree/master/components/bt/host/nimble)
<br/>
# Acknowledgments
@ -82,10 +82,4 @@ Also tracking the NimBLE related changes in ESP-IDF, master branch, currently [@
* [beegee-tokyo](https://github.com/beegee-tokyo) for contributing your time to test/debug and contributing the beacon examples.
* [Jeroen88](https://github.com/Jeroen88) for the amazing help debugging and improving the client code.
<br/>
# Todo
- Improve host reset handler
- Implement random address handling
- Implement bond management
- Add Bluetooth Mesh
<br/>

View File

@ -69,8 +69,6 @@ For example `BLEServer::createService(SERVICE_UUID)` will work just as it did be
<a name="characteristics"></a>
### Characteristics
The constructor for `(Nim)BLECharacteristic` is now private, so if you currently subclass it to add logic you should switch to use `NimBLEService::createCharacteristic` instead. Any custom processing logic previously in a `BLECharacteristic` subclass should be moved to a `NimBLECharacteristicCallbacks` subclass instead, and passed into `NimBLECharacteristic::setCallbacks`.
`BLEService::createCharacteristic` (`NimBLEService::createCharacteristic`) is used the same way as originally except the properties parameter has changed.
When creating a characteristic the properties are now set with `NIMBLE_PROPERTY::XXXX` instead of `BLECharacteristic::XXXX`.

View File

@ -0,0 +1,67 @@
/*
* NimBLE_Scan_Whitelist demo
*
* Created May 16, 2021
* Author: h2zero
*/
#include <NimBLEDevice.h>
int scanTime = 5; //In seconds
NimBLEScan* pBLEScan;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice* advertisedDevice) {
Serial.printf("Advertised Device: %s \n", advertisedDevice->toString().c_str());
/*
* Here we add the device scanned to the whitelist based on service data but any
* advertised data can be used for your preffered data.
*/
if (advertisedDevice->haveServiceData()) {
/* If this is a device with data we want to capture, add it to the whitelist */
if (advertisedDevice->getServiceData(NimBLEUUID("AABB")) != "") {
Serial.printf("Adding %s to whitelist\n", std::string(advertisedDevice->getAddress()).c_str());
NimBLEDevice::whiteListAdd(advertisedDevice->getAddress());
}
}
}
};
void setup() {
Serial.begin(115200);
Serial.println("Scanning...");
NimBLEDevice::init("");
pBLEScan = NimBLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true);
pBLEScan->setInterval(100);
pBLEScan->setFilterPolicy(BLE_HCI_SCAN_FILT_NO_WL);
pBLEScan->setWindow(99);
}
void loop() {
NimBLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
Serial.println("Whitelist contains:");
for (auto i=0; i<NimBLEDevice::getWhiteListCount(); ++i) {
Serial.println(NimBLEDevice::getWhiteListAddress(i).toString().c_str());
}
/*
* If we have addresses in the whitelist enable the filter unless no devices were found
* then scan without so we can find any new devices that we want.
*/
if (NimBLEDevice::getWhiteListCount() > 0) {
if (foundDevices.getCount() == 0) {
pBLEScan->setFilterPolicy(BLE_HCI_SCAN_FILT_NO_WL);
} else {
pBLEScan->setFilterPolicy(BLE_HCI_SCAN_FILT_USE_WL);
}
}
pBLEScan->clearResults();
delay(2000);
}

View File

@ -39,6 +39,9 @@ class ServerCallbacks: public NimBLEServerCallbacks {
Serial.println("Client disconnected - start advertising");
NimBLEDevice::startAdvertising();
};
void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
Serial.printf("MTU updated: %u for connection ID: %u\n", MTU, desc->conn_handle);
};
/********************* Security handled here **********************
****** Note: these are the same return values as defaults ********/

View File

@ -0,0 +1,105 @@
/*
* NimBLE_Server_Whitelist demo
*
* Created May 17, 2021
* Author: h2zero
*/
#include <NimBLEDevice.h>
NimBLECharacteristic* pCharacteristic = nullptr;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
class MyServerCallbacks: public NimBLEServerCallbacks {
void onConnect(NimBLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc) {
// Peer disconnected, add them to the whitelist
// This allows us to use the whitelist to filter connection attempts
// which will minimize reconnection time.
NimBLEDevice::whiteListAdd(NimBLEAddress(desc->peer_ota_addr));
deviceConnected = false;
}
};
void onAdvComplete(NimBLEAdvertising *pAdvertising) {
Serial.println("Advertising stopped");
if (deviceConnected) {
return;
}
// If advertising timed out without connection start advertising without whitelist filter
pAdvertising->setScanFilter(false,false);
pAdvertising->start();
}
void setup() {
Serial.begin(115200);
// Create the BLE Device
NimBLEDevice::init("ESP32");
// Create the BLE Server
NimBLEServer* pServer = NimBLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
pServer->advertiseOnDisconnect(false);
// Create the BLE Service
NimBLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE |
NIMBLE_PROPERTY::NOTIFY );
// Start the service
pService->start();
// Start advertising
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(false);
pAdvertising->start();
Serial.println("Waiting a client connection to notify...");
}
void loop() {
// notify changed value
if (deviceConnected) {
pCharacteristic->setValue((uint8_t*)&value, 4);
pCharacteristic->notify();
value++;
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
if (NimBLEDevice::getWhiteListCount() > 0) {
// Allow anyone to scan but only whitelisted can connect.
pAdvertising->setScanFilter(false,true);
}
// advertise with whitelist for 30 seconds
pAdvertising->start(30, onAdvComplete);
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
delay(2000);
}

View File

@ -2,7 +2,7 @@
"name": "NimBLE-Arduino",
"keywords": "esp32, bluetooth",
"description": "Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE",
"version": "1.2.0",
"version": "1.3.1",
"frameworks": "arduino",
"platforms": "espressif32"
}

View File

@ -1,5 +1,5 @@
name=NimBLE-Arduino
version=1.2.0
version=1.3.1
author=h2zero
maintainer=h2zero <powellperalta@gmail.com>
sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE.

View File

@ -1,316 +0,0 @@
/*
* FreeRTOS.cpp
*
* Created on: Feb 24, 2017
* Author: kolban
*/
#include "sdkconfig.h"
#include "FreeRTOS.h"
#include "NimBLELog.h"
#include <freertos/FreeRTOS.h> // Include the base FreeRTOS definitions
#include <freertos/task.h> // Include the task definitions
#include <freertos/semphr.h> // Include the semaphore definitions
#include <string>
static const char* LOG_TAG = "FreeRTOS";
/**
* Sleep for the specified number of milliseconds.
* @param[in] ms The period in milliseconds for which to sleep.
*/
void FreeRTOS::sleep(uint32_t ms) {
::vTaskDelay(ms / portTICK_PERIOD_MS);
} // sleep
/**
* Start a new task.
* @param[in] task The function pointer to the function to be run in the task.
* @param[in] taskName A string identifier for the task.
* @param[in] param An optional parameter to be passed to the started task.
* @param[in] stackSize An optional paremeter supplying the size of the stack in which to run the task.
*/
void FreeRTOS::startTask(void task(void*), std::string taskName, void* param, uint32_t stackSize) {
::xTaskCreate(task, taskName.data(), stackSize, param, 5, NULL);
} // startTask
/**
* Delete the task.
* @param[in] pTask An optional handle to the task to be deleted. If not supplied the calling task will be deleted.
*/
void FreeRTOS::deleteTask(TaskHandle_t pTask) {
::vTaskDelete(pTask);
} // deleteTask
/**
* Get the time in milliseconds since the %FreeRTOS scheduler started.
* @return The time in milliseconds since the %FreeRTOS scheduler started.
*/
uint32_t FreeRTOS::getTimeSinceStart() {
return (uint32_t) (xTaskGetTickCount() * portTICK_PERIOD_MS);
} // getTimeSinceStart
/**
* @brief Wait for a semaphore to be released by trying to take it and
* then releasing it again.
* @param [in] owner A debug tag.
* @return The value associated with the semaphore.
*/
uint32_t FreeRTOS::Semaphore::wait(std::string owner) {
NIMBLE_LOGD(LOG_TAG, ">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
if (m_usePthreads) {
pthread_mutex_lock(&m_pthread_mutex);
} else {
xSemaphoreTake(m_semaphore, portMAX_DELAY);
}
if (m_usePthreads) {
pthread_mutex_unlock(&m_pthread_mutex);
} else {
xSemaphoreGive(m_semaphore);
}
NIMBLE_LOGD(LOG_TAG, "<< wait: Semaphore released: %s", toString().c_str());
return m_value;
} // wait
/**
* @brief Wait for a semaphore to be released in a given period of time by trying to take it and
* then releasing it again. The value associated with the semaphore can be taken by value() call after return
* @param [in] owner A debug tag.
* @param [in] timeoutMs timeout to wait in ms.
* @return True if we took the semaphore within timeframe.
*/
bool FreeRTOS::Semaphore::timedWait(std::string owner, uint32_t timeoutMs) {
NIMBLE_LOGD(LOG_TAG, ">> wait: Semaphore waiting: %s for %s", toString().c_str(), owner.c_str());
if (m_usePthreads && timeoutMs != portMAX_DELAY) {
assert(false); // We apparently don't have a timed wait for pthreads.
}
auto ret = pdTRUE;
if (m_usePthreads) {
pthread_mutex_lock(&m_pthread_mutex);
} else {
ret = xSemaphoreTake(m_semaphore, timeoutMs);
}
if (m_usePthreads) {
pthread_mutex_unlock(&m_pthread_mutex);
} else {
xSemaphoreGive(m_semaphore);
}
NIMBLE_LOGD(LOG_TAG, "<< wait: Semaphore %s released: %d", toString().c_str(), ret);
return ret;
} // wait
/**
* @brief Construct a semaphore, the semaphore is given when created.
* @param [in] name A name string to provide debugging support.
*/
FreeRTOS::Semaphore::Semaphore(std::string name) {
m_usePthreads = false; // Are we using pThreads or FreeRTOS?
if (m_usePthreads) {
pthread_mutex_init(&m_pthread_mutex, nullptr);
} else {
//m_semaphore = xSemaphoreCreateMutex();
m_semaphore = xSemaphoreCreateBinary();
xSemaphoreGive(m_semaphore);
}
m_name = name;
m_owner = std::string("<N/A>");
m_value = 0;
}
FreeRTOS::Semaphore::~Semaphore() {
if (m_usePthreads) {
pthread_mutex_destroy(&m_pthread_mutex);
} else {
vSemaphoreDelete(m_semaphore);
}
}
/**
* @brief Give the semaphore.
*/
void FreeRTOS::Semaphore::give() {
NIMBLE_LOGD(LOG_TAG, "Semaphore giving: %s", toString().c_str());
m_owner = std::string("<N/A>");
if (m_usePthreads) {
pthread_mutex_unlock(&m_pthread_mutex);
} else {
xSemaphoreGive(m_semaphore);
}
// #ifdef ARDUINO_ARCH_ESP32
// FreeRTOS::sleep(10);
// #endif
} // Semaphore::give
/**
* @brief Give a semaphore.
* The Semaphore is given with an associated value.
* @param [in] value The value to associate with the semaphore.
*/
void FreeRTOS::Semaphore::give(uint32_t value) {
m_value = value;
give();
} // give
/**
* @brief Give a semaphore from an ISR.
*/
void FreeRTOS::Semaphore::giveFromISR() {
BaseType_t higherPriorityTaskWoken;
if (m_usePthreads) {
assert(false);
} else {
xSemaphoreGiveFromISR(m_semaphore, &higherPriorityTaskWoken);
}
} // giveFromISR
/**
* @brief Take a semaphore.
* Take a semaphore and wait indefinitely.
* @param [in] owner The new owner (for debugging)
* @return True if we took the semaphore.
*/
bool FreeRTOS::Semaphore::take(std::string owner) {
NIMBLE_LOGD(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
bool rc = false;
if (m_usePthreads) {
pthread_mutex_lock(&m_pthread_mutex);
} else {
rc = ::xSemaphoreTake(m_semaphore, portMAX_DELAY) == pdTRUE;
}
m_owner = owner;
if (rc) {
NIMBLE_LOGD(LOG_TAG, "Semaphore taken: %s", toString().c_str());
} else {
NIMBLE_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str());
}
return rc;
} // Semaphore::take
/**
* @brief Take a semaphore.
* Take a semaphore but return if we haven't obtained it in the given period of milliseconds.
* @param [in] timeoutMs Timeout in milliseconds.
* @param [in] owner The new owner (for debugging)
* @return True if we took the semaphore.
*/
bool FreeRTOS::Semaphore::take(uint32_t timeoutMs, std::string owner) {
NIMBLE_LOGD(LOG_TAG, "Semaphore taking: %s for %s", toString().c_str(), owner.c_str());
bool rc = false;
if (m_usePthreads) {
assert(false); // We apparently don't have a timed wait for pthreads.
} else {
rc = ::xSemaphoreTake(m_semaphore, timeoutMs / portTICK_PERIOD_MS) == pdTRUE;
}
m_owner = owner;
if (rc) {
NIMBLE_LOGD(LOG_TAG, "Semaphore taken: %s", toString().c_str());
} else {
NIMBLE_LOGE(LOG_TAG, "Semaphore NOT taken: %s", toString().c_str());
}
return rc;
} // Semaphore::take
/**
* @brief Create a string representation of the semaphore.
* @return A string representation of the semaphore.
*/
std::string FreeRTOS::Semaphore::toString() {
char hex[9];
std::string res = "name: " + m_name + " (0x";
snprintf(hex, sizeof(hex), "%08x", (uint32_t)m_semaphore);
res += hex;
res += "), owner: " + m_owner;
return res;
} // toString
/**
* @brief Set the name of the semaphore.
* @param [in] name The name of the semaphore.
*/
void FreeRTOS::Semaphore::setName(std::string name) {
m_name = name;
} // setName
/**
* @brief Create a ring buffer.
* @param [in] length The amount of storage to allocate for the ring buffer.
* @param [in] type The type of buffer. One of RINGBUF_TYPE_NOSPLIT, RINGBUF_TYPE_ALLOWSPLIT, RINGBUF_TYPE_BYTEBUF.
*/
#ifdef ESP_IDF_VERSION //Quick hack to detect if using IDF version that replaced ringbuf_type_t
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
Ringbuffer::Ringbuffer(size_t length, RingbufferType_t type) {
#else
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) {
#endif
#else
Ringbuffer::Ringbuffer(size_t length, ringbuf_type_t type) {
#endif
m_handle = ::xRingbufferCreate(length, type);
} // Ringbuffer
Ringbuffer::~Ringbuffer() {
::vRingbufferDelete(m_handle);
} // ~Ringbuffer
/**
* @brief Receive data from the buffer.
* @param [out] size On return, the size of data returned.
* @param [in] wait How long to wait.
* @return A pointer to the storage retrieved.
*/
void* Ringbuffer::receive(size_t* size, TickType_t wait) {
return ::xRingbufferReceive(m_handle, size, wait);
} // receive
/**
* @brief Return an item.
* @param [in] item The item to be returned/released.
*/
void Ringbuffer::returnItem(void* item) {
::vRingbufferReturnItem(m_handle, item);
} // returnItem
/**
* @brief Send data to the buffer.
* @param [in] data The data to place into the buffer.
* @param [in] length The length of data to place into the buffer.
* @param [in] wait How long to wait before giving up. The default is to wait indefinitely.
* @return
*/
bool Ringbuffer::send(void* data, size_t length, TickType_t wait) {
return ::xRingbufferSend(m_handle, data, length, wait) == pdTRUE;
} // send

View File

@ -1,89 +0,0 @@
/*
* FreeRTOS.h
*
* Created on: Feb 24, 2017
* Author: kolban
*/
#ifndef MAIN_FREERTOS_H_
#define MAIN_FREERTOS_H_
#include <freertos/FreeRTOS.h> // Include the base FreeRTOS definitions.
#include <freertos/task.h> // Include the task definitions.
#include <freertos/semphr.h> // Include the semaphore definitions.
#include <freertos/ringbuf.h> // Include the ringbuffer definitions.
#include <stdint.h>
#include <string>
#include <pthread.h>
/**
* @brief Interface to %FreeRTOS functions.
*/
class FreeRTOS {
public:
static void sleep(uint32_t ms);
static void startTask(void task(void*), std::string taskName, void* param = nullptr, uint32_t stackSize = 2048);
static void deleteTask(TaskHandle_t pTask = nullptr);
static uint32_t getTimeSinceStart();
/**
* @brief A binary semaphore class that operates like a mutex, it is already given when constructed.
*/
class Semaphore {
public:
Semaphore(std::string owner = "<Unknown>");
~Semaphore();
void give();
void give(uint32_t value);
void giveFromISR();
void setName(std::string name);
bool take(std::string owner = "<Unknown>");
bool take(uint32_t timeoutMs, std::string owner = "<Unknown>");
std::string toString();
bool timedWait(std::string owner = "<Unknown>", uint32_t timeoutMs = portMAX_DELAY);
uint32_t wait(std::string owner = "<Unknown>");
/**
* @brief Get the value of the semaphore.
* @return The value stored if the semaphore was given with give(value);
*/
uint32_t value(){ return m_value; };
private:
SemaphoreHandle_t m_semaphore;
pthread_mutex_t m_pthread_mutex;
std::string m_name;
std::string m_owner;
uint32_t m_value;
bool m_usePthreads;
};
};
/**
* @brief A wrapper class for a freeRTOS ringbuffer.
*/
class Ringbuffer {
public:
#ifdef ESP_IDF_VERSION //Quick hack to detect if using IDF version that replaced ringbuf_type_t
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
Ringbuffer(size_t length, RingbufferType_t type = RINGBUF_TYPE_NOSPLIT);
#else
Ringbuffer(size_t length, ringbuf_type_t type = RINGBUF_TYPE_NOSPLIT);
#endif
#else
Ringbuffer(size_t length, ringbuf_type_t type = RINGBUF_TYPE_NOSPLIT);
#endif
~Ringbuffer();
void* receive(size_t* size, TickType_t wait = portMAX_DELAY);
void returnItem(void* item);
bool send(void* data, size_t length, TickType_t wait = portMAX_DELAY);
private:
RingbufHandle_t m_handle;
};
#endif /* MAIN_FREERTOS_H_ */

View File

@ -42,6 +42,7 @@ struct BLE2904_Data {
*/
class NimBLE2904: public NimBLEDescriptor {
public:
NimBLE2904(NimBLECharacteristic* pCharacterisitic = nullptr);
static const uint8_t FORMAT_BOOLEAN = 1;
static const uint8_t FORMAT_UINT2 = 2;
static const uint8_t FORMAT_UINT4 = 3;
@ -77,7 +78,6 @@ public:
void setUnit(uint16_t unit);
private:
NimBLE2904(NimBLECharacteristic* pCharacterisitic);
friend class NimBLECharacteristic;
BLE2904_Data m_data;
}; // BLE2904

View File

@ -734,7 +734,7 @@ uint8_t* NimBLEAdvertisedDevice::getPayload() {
* @param [in] length The length of the payload in bytes.
* @param [in] append Indicates if the the data should be appended (scan response).
*/
void NimBLEAdvertisedDevice::setPayload(uint8_t *payload, uint8_t length, bool append) {
void NimBLEAdvertisedDevice::setPayload(const uint8_t *payload, uint8_t length, bool append) {
if(!append) {
m_advLength = length;
m_payload.assign(payload, payload + length);

View File

@ -137,7 +137,7 @@ private:
void setAddress(NimBLEAddress address);
void setAdvType(uint8_t advType);
void setPayload(uint8_t *payload, uint8_t length, bool append);
void setPayload(const uint8_t *payload, uint8_t length, bool append);
void setRSSI(int rssi);
uint8_t findAdvField(uint8_t type, uint8_t index = 0, uint8_t *data_loc = nullptr);
uint8_t findServiceData(uint8_t index, uint8_t* bytes);

View File

@ -383,6 +383,7 @@ void NimBLEAdvertising::setScanResponseData(NimBLEAdvertisementData& advertiseme
* @brief Start advertising.
* @param [in] duration The duration, in seconds, to advertise, 0 == advertise forever.
* @param [in] advCompleteCB A pointer to a callback to be invoked when advertising ends.
* @return True if advertising started successfully.
*/
bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdvertising *pAdv)) {
NIMBLE_LOGD(LOG_TAG, ">> Advertising start: customAdvData: %d, customScanResponseData: %d",
@ -471,16 +472,14 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
}
payloadLen += add;
if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc(m_advData.uuids16,
if(nullptr == (m_advData.uuids16 = (ble_uuid16_t*)realloc((void*)m_advData.uuids16,
(m_advData.num_uuids16 + 1) * sizeof(ble_uuid16_t))))
{
NIMBLE_LOGC(LOG_TAG, "Error, no mem");
abort();
}
memcpy(&m_advData.uuids16[m_advData.num_uuids16].value,
&it.getNative()->u16.value, 2);
m_advData.uuids16[m_advData.num_uuids16].u.type = BLE_UUID_TYPE_16;
memcpy((void*)&m_advData.uuids16[m_advData.num_uuids16],
&it.getNative()->u16, sizeof(ble_uuid16_t));
m_advData.uuids16_is_complete = 1;
m_advData.num_uuids16++;
}
@ -492,16 +491,14 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
}
payloadLen += add;
if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc(m_advData.uuids32,
if(nullptr == (m_advData.uuids32 = (ble_uuid32_t*)realloc((void*)m_advData.uuids32,
(m_advData.num_uuids32 + 1) * sizeof(ble_uuid32_t))))
{
NIMBLE_LOGC(LOG_TAG, "Error, no mem");
abort();
}
memcpy(&m_advData.uuids32[m_advData.num_uuids32].value,
&it.getNative()->u32.value, 4);
m_advData.uuids32[m_advData.num_uuids32].u.type = BLE_UUID_TYPE_32;
memcpy((void*)&m_advData.uuids32[m_advData.num_uuids32],
&it.getNative()->u32, sizeof(ble_uuid32_t));
m_advData.uuids32_is_complete = 1;
m_advData.num_uuids32++;
}
@ -513,16 +510,14 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
}
payloadLen += add;
if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc(m_advData.uuids128,
if(nullptr == (m_advData.uuids128 = (ble_uuid128_t*)realloc((void*)m_advData.uuids128,
(m_advData.num_uuids128 + 1) * sizeof(ble_uuid128_t))))
{
NIMBLE_LOGC(LOG_TAG, "Error, no mem");
abort();
}
memcpy(&m_advData.uuids128[m_advData.num_uuids128].value,
&it.getNative()->u128.value, 16);
m_advData.uuids128[m_advData.num_uuids128].u.type = BLE_UUID_TYPE_128;
memcpy((void*)&m_advData.uuids128[m_advData.num_uuids128],
&it.getNative()->u128, sizeof(ble_uuid128_t));
m_advData.uuids128_is_complete = 1;
m_advData.num_uuids128++;
}
@ -599,19 +594,19 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
}
if(m_advData.num_uuids128 > 0) {
free(m_advData.uuids128);
free((void*)m_advData.uuids128);
m_advData.uuids128 = nullptr;
m_advData.num_uuids128 = 0;
}
if(m_advData.num_uuids32 > 0) {
free(m_advData.uuids32);
free((void*)m_advData.uuids32);
m_advData.uuids32 = nullptr;
m_advData.num_uuids32 = 0;
}
if(m_advData.num_uuids16 > 0) {
free(m_advData.uuids16);
free((void*)m_advData.uuids16);
m_advData.uuids16 = nullptr;
m_advData.num_uuids16 = 0;
}

View File

@ -45,15 +45,15 @@ NimBLECharacteristic::NimBLECharacteristic(const char* uuid, uint16_t properties
* @param [in] pService - pointer to the service instance this characteristic belongs to.
*/
NimBLECharacteristic::NimBLECharacteristic(const NimBLEUUID &uuid, uint16_t properties, NimBLEService* pService) {
m_uuid = uuid;
m_handle = NULL_HANDLE;
m_properties = properties;
m_pCallbacks = &defaultCallback;
m_pService = pService;
m_value = "";
m_valMux = portMUX_INITIALIZER_UNLOCKED;
m_pTaskData = nullptr;
m_timestamp = 0;
m_uuid = uuid;
m_handle = NULL_HANDLE;
m_properties = properties;
m_pCallbacks = &defaultCallback;
m_pService = pService;
m_value = "";
m_valMux = portMUX_INITIALIZER_UNLOCKED;
m_timestamp = 0;
m_removed = 0;
} // NimBLECharacteristic
/**
@ -95,9 +95,62 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid,
pDescriptor = new NimBLEDescriptor(uuid, properties, max_len, this);
}
m_dscVec.push_back(pDescriptor);
addDescriptor(pDescriptor);
return pDescriptor;
} // createCharacteristic
} // createDescriptor
/**
* @brief Add a descriptor to the characteristic.
* @param [in] pDescriptor A pointer to the descriptor to add.
*/
void NimBLECharacteristic::addDescriptor(NimBLEDescriptor *pDescriptor) {
bool foundRemoved = false;
if(pDescriptor->m_removed > 0) {
for(auto& it : m_dscVec) {
if(it == pDescriptor) {
foundRemoved = true;
pDescriptor->m_removed = 0;
}
}
}
if(!foundRemoved) {
m_dscVec.push_back(pDescriptor);
}
pDescriptor->setCharacteristic(this);
NimBLEDevice::getServer()->serviceChanged();
}
/**
* @brief Remove a descriptor from the characterisitc.
* @param[in] pDescriptor A pointer to the descriptor instance to remove from the characterisitc.
* @param[in] deleteDsc If true it will delete the descriptor instance and free it's resources.
*/
void NimBLECharacteristic::removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc) {
// Check if the descriptor was already removed and if so, check if this
// is being called to delete the object and do so if requested.
// Otherwise, ignore the call and return.
if(pDescriptor->m_removed > 0) {
if(deleteDsc) {
for(auto it = m_dscVec.begin(); it != m_dscVec.end(); ++it) {
if ((*it) == pDescriptor) {
delete *it;
m_dscVec.erase(it);
break;
}
}
}
return;
}
pDescriptor->m_removed = deleteDsc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
NimBLEDevice::getServer()->serviceChanged();
} // removeDescriptor
/**
@ -165,6 +218,11 @@ NimBLEService* NimBLECharacteristic::getService() {
} // getService
void NimBLECharacteristic::setService(NimBLEService *pService) {
m_pService = pService;
}
/**
* @brief Get the UUID of the characteristic.
* @return The UUID of the characteristic.
@ -301,16 +359,13 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
subVal |= NIMBLE_SUB_INDICATE;
}
if(m_pTaskData != nullptr) {
m_pTaskData->rc = (subVal & NIMBLE_SUB_INDICATE) ? 0 :
NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_DISABLED;
xTaskNotifyGive(m_pTaskData->task);
}
NIMBLE_LOGI(LOG_TAG, "New subscribe value for conn: %d val: %d",
event->subscribe.conn_handle, subVal);
event->subscribe.conn_handle, subVal);
if(!event->subscribe.cur_indicate && event->subscribe.prev_indicate) {
NimBLEDevice::getServer()->clearIndicateWait(event->subscribe.conn_handle);
}
m_pCallbacks->onSubscribe(this, &desc, subVal);
auto it = m_subscribedVec.begin();
for(;it != m_subscribedVec.end(); ++it) {
@ -322,16 +377,14 @@ void NimBLECharacteristic::setSubscribe(struct ble_gap_event *event) {
if(subVal > 0) {
if(it == m_subscribedVec.end()) {
m_subscribedVec.push_back({event->subscribe.conn_handle, subVal});
return;
} else {
(*it).second = subVal;
}
(*it).second = subVal;
} else if(it != m_subscribedVec.end()) {
m_subscribedVec.erase(it);
m_subscribedVec.shrink_to_fit();
}
m_pCallbacks->onSubscribe(this, &desc, subVal);
}
@ -416,40 +469,20 @@ void NimBLECharacteristic::notify(bool is_notification) {
// We also must create it in each loop iteration because it is consumed with each host call.
os_mbuf *om = ble_hs_mbuf_from_flat((uint8_t*)value.data(), length);
NimBLECharacteristicCallbacks::Status statusRC;
if(!is_notification && (m_properties & NIMBLE_PROPERTY::INDICATE)) {
ble_task_data_t taskData = {nullptr, xTaskGetCurrentTaskHandle(),0, nullptr};
m_pTaskData = &taskData;
if(!NimBLEDevice::getServer()->setIndicateWait(it.first)) {
NIMBLE_LOGE(LOG_TAG, "prior Indication in progress");
os_mbuf_free_chain(om);
return;
}
rc = ble_gattc_indicate_custom(it.first, m_handle, om);
if(rc != 0){
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
} else {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
rc = m_pTaskData->rc;
}
m_pTaskData = nullptr;
if(rc == BLE_HS_EDONE) {
rc = 0;
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
} else if(rc == BLE_HS_ETIMEOUT) {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
} else {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
NimBLEDevice::getServer()->clearIndicateWait(it.first);
}
} else {
rc = ble_gattc_notify_custom(it.first, m_handle, om);
if(rc == 0) {
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
} else {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
}
ble_gattc_notify_custom(it.first, m_handle, om);
}
m_pCallbacks->onStatus(this, statusRC, rc);
}
NIMBLE_LOGD(LOG_TAG, "<< notify");
@ -469,6 +502,13 @@ void NimBLECharacteristic::setCallbacks(NimBLECharacteristicCallbacks* pCallback
}
} // setCallbacks
/**
* @brief Get the callback handlers for this characteristic.
*/
NimBLECharacteristicCallbacks* NimBLECharacteristic::getCallbacks() {
return m_pCallbacks;
} //getCallbacks
/**
* @brief Set the value of the characteristic.

View File

@ -59,12 +59,26 @@ class NimBLECharacteristicCallbacks;
*/
class NimBLECharacteristic {
public:
NimBLECharacteristic(const char* uuid,
uint16_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
NimBLEService* pService = nullptr);
NimBLECharacteristic(const NimBLEUUID &uuid,
uint16_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
NimBLEService* pService = nullptr);
~NimBLECharacteristic();
uint16_t getHandle();
NimBLEUUID getUUID();
std::string toString();
void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
NimBLECharacteristicCallbacks*
getCallbacks();
void indicate();
void notify(bool is_notification = true);
@ -81,9 +95,11 @@ public:
NIMBLE_PROPERTY::WRITE,
uint16_t max_len = 100);
void addDescriptor(NimBLEDescriptor *pDescriptor);
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
void removeDescriptor(NimBLEDescriptor *pDescriptor, bool deleteDsc = false);
std::string getValue(time_t *timestamp = nullptr);
size_t getDataLength();
@ -115,30 +131,15 @@ public:
setValue((uint8_t*)&s, sizeof(T));
}
NimBLEService* getService();
uint16_t getProperties();
private:
friend class NimBLEServer;
friend class NimBLEService;
friend class NimBLEServer;
friend class NimBLEService;
NimBLECharacteristic(const char* uuid,
uint16_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
NimBLEService* pService = nullptr);
NimBLECharacteristic(const NimBLEUUID &uuid,
uint16_t properties =
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE,
NimBLEService* pService = nullptr);
~NimBLECharacteristic();
NimBLEService* getService();
uint16_t getProperties();
void setService(NimBLEService *pService);
void setSubscribe(struct ble_gap_event *event);
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
@ -150,9 +151,9 @@ private:
NimBLEService* m_pService;
std::string m_value;
std::vector<NimBLEDescriptor*> m_dscVec;
ble_task_data_t *m_pTaskData;
portMUX_TYPE m_valMux;
time_t m_timestamp;
uint8_t m_removed;
std::vector<std::pair<uint16_t, uint16_t>> m_subscribedVec;
}; // NimBLECharacteristic

View File

@ -436,6 +436,24 @@ void NimBLEClient::updateConnParams(uint16_t minInterval, uint16_t maxInterval,
} // updateConnParams
/**
* @brief Get detailed information about the current peer connection.
*/
NimBLEConnInfo NimBLEClient::getConnInfo() {
NimBLEConnInfo connInfo;
if (!isConnected()) {
NIMBLE_LOGE(LOG_TAG, "Not connected");
} else {
int rc = ble_gap_conn_find(m_conn_id, &connInfo.m_desc);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Connection info not found");
}
}
return connInfo;
} // getConnInfo
/**
* @brief Set the timeout to wait for connection attempt to complete.
* @param [in] time The number of seconds before timeout.

View File

@ -23,6 +23,7 @@
#include "NimBLEAddress.h"
#include "NimBLEUUID.h"
#include "NimBLEUtils.h"
#include "NimBLEConnInfo.h"
#include "NimBLEAdvertisedDevice.h"
#include "NimBLERemoteService.h"
@ -71,6 +72,7 @@ public:
void updateConnParams(uint16_t minInterval, uint16_t maxInterval,
uint16_t latency, uint16_t timeout);
void discoverAttributes();
NimBLEConnInfo getConnInfo();
private:
NimBLEClient(const NimBLEAddress &peerAddress);

View File

@ -0,0 +1,55 @@
#ifndef NIMBLECONNINFO_H_
#define NIMBLECONNINFO_H_
#include "NimBLEAddress.h"
/**
* @brief Connection information.
*/
class NimBLEConnInfo {
friend class NimBLEServer;
friend class NimBLEClient;
ble_gap_conn_desc m_desc;
NimBLEConnInfo() { m_desc = {}; }
NimBLEConnInfo(ble_gap_conn_desc desc) { m_desc = desc; }
public:
/** @brief Gets the over-the-air address of the connected peer */
NimBLEAddress getAddress() { return NimBLEAddress(m_desc.peer_ota_addr); }
/** @brief Gets the ID address of the connected peer */
NimBLEAddress getIdAddress() { return NimBLEAddress(m_desc.peer_id_addr); }
/** @brief Gets the connection handle of the connected peer */
uint16_t getConnHandle() { return m_desc.conn_handle; }
/** @brief Gets the connection interval for this connection (in 1.25ms units) */
uint16_t getConnInterval() { return m_desc.conn_itvl; }
/** @brief Gets the supervision timeout for this connection (in 10ms units) */
uint16_t getConnTimeout() { return m_desc.supervision_timeout; }
/** @brief Gets the allowable latency for this connection (unit = number of intervals) */
uint16_t getConnLatency() { return m_desc.conn_latency; }
/** @brief Gets the maximum transmission unit size for this connection (in bytes) */
uint16_t getMTU() { return ble_att_mtu(m_desc.conn_handle); }
/** @brief Check if we are in the master role in this connection */
bool isMaster() { return (m_desc.role == BLE_GAP_ROLE_MASTER); }
/** @brief Check if we are in the slave role in this connection */
bool isSlave() { return (m_desc.role == BLE_GAP_ROLE_SLAVE); }
/** @brief Check if we are connected to a bonded peer */
bool isBonded() { return (m_desc.sec_state.bonded == 1); }
/** @brief Check if the connection in encrypted */
bool isEncrypted() { return (m_desc.sec_state.encrypted == 1); }
/** @brief Check if the the connection has been authenticated */
bool isAuthenticated() { return (m_desc.sec_state.authenticated == 1); }
/** @brief Gets the key size used to encrypt the connection */
uint8_t getSecKeySize() { return m_desc.sec_state.key_size; }
};
#endif

View File

@ -37,6 +37,7 @@ NimBLEDescriptor::NimBLEDescriptor(const char* uuid, uint16_t properties, uint16
: NimBLEDescriptor(NimBLEUUID(uuid), max_len, properties, pCharacteristic) {
}
/**
* @brief NimBLEDescriptor constructor.
*/
@ -47,11 +48,12 @@ NimBLEDescriptor::NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties, uint16_
m_value.attr_len = 0; // Initial length is 0.
m_value.attr_max_len = max_len; // Maximum length of the data.
m_handle = NULL_HANDLE; // Handle is initially unknown.
m_pCharacteristic = nullptr; // No initial characteristic.
m_pCharacteristic = pCharacteristic;
m_pCallbacks = &defaultCallbacks; // No initial callback.
m_value.attr_value = (uint8_t*) calloc(max_len,1); // Allocate storage for the value.
m_valMux = portMUX_INITIALIZER_UNLOCKED;
m_properties = 0;
m_removed = 0;
if (properties & BLE_GATT_CHR_F_READ) { // convert uint16_t properties to uint8_t
m_properties |= BLE_ATT_F_READ;
@ -122,6 +124,7 @@ uint8_t* NimBLEDescriptor::getValue() {
return m_value.attr_value;
} // getValue
/**
* @brief Get the value of this descriptor as a string.
* @return A std::string instance containing a copy of the descriptor's value.
@ -130,9 +133,18 @@ std::string NimBLEDescriptor::getStringValue() {
return std::string((char *) m_value.attr_value, m_value.attr_len);
}
/**
* @brief Get the characteristic this descriptor belongs to.
* @return A pointer to the characteristic this descriptor belongs to.
*/
NimBLECharacteristic* NimBLEDescriptor::getCharacteristic() {
return m_pCharacteristic;
} // getCharacteristic
int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt,
void *arg) {
struct ble_gatt_access_ctxt *ctxt, void *arg) {
const ble_uuid_t *uuid;
int rc;
NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;
@ -169,7 +181,7 @@ int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
if((len + next->om_len) > pDescriptor->m_value.attr_max_len) {
return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN;
}
memcpy(&buf[len-1], next->om_data, next->om_len);
memcpy(&buf[len], next->om_data, next->om_len);
len += next->om_len;
next = SLIST_NEXT(next, om_next);
}
@ -237,6 +249,14 @@ void NimBLEDescriptor::setValue(const std::string &value) {
setValue((uint8_t*) value.data(), value.length());
} // setValue
/**
* @brief Set the characteristic this descriptor belongs to.
* @param [in] pChar A pointer to the characteristic this descriptior belongs to.
*/
void NimBLEDescriptor::setCharacteristic(NimBLECharacteristic* pChar) {
m_pCharacteristic = pChar;
} // setCharacteristic
/**
* @brief Return a string representation of the descriptor.

View File

@ -43,46 +43,48 @@ class NimBLEDescriptorCallbacks;
*/
class NimBLEDescriptor {
public:
uint16_t getHandle();
NimBLEUUID getUUID();
std::string toString();
NimBLEDescriptor(const char* uuid, uint16_t properties,
uint16_t max_len,
NimBLECharacteristic* pCharacteristic = nullptr);
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
uint16_t max_len,
NimBLECharacteristic* pCharacteristic = nullptr);
size_t getLength();
uint8_t* getValue();
std::string getStringValue();
~NimBLEDescriptor();
uint16_t getHandle();
NimBLEUUID getUUID();
std::string toString();
void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
size_t getLength();
uint8_t* getValue();
std::string getStringValue();
void setValue(const uint8_t* data, size_t size);
void setValue(const std::string &value);
NimBLECharacteristic* getCharacteristic();
void setValue(const uint8_t* data, size_t size);
void setValue(const std::string &value);
/**
* @brief Convenience template to set the descriptor value to <type\>val.
* @param [in] s The value to set.
*/
template<typename T>
void setValue(const T &s) {
void setValue(const T &s) {
setValue((uint8_t*)&s, sizeof(T));
}
private:
friend class NimBLECharacteristic;
friend class NimBLEService;
friend class NimBLE2902;
friend class NimBLE2904;
NimBLEDescriptor(const char* uuid, uint16_t properties,
uint16_t max_len,
NimBLECharacteristic* pCharacteristic);
NimBLEDescriptor(NimBLEUUID uuid, uint16_t properties,
uint16_t max_len,
NimBLECharacteristic* pCharacteristic);
~NimBLEDescriptor();
static int handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg);
void setHandle(uint16_t handle);
void setCharacteristic(NimBLECharacteristic* pChar);
NimBLEUUID m_uuid;
uint16_t m_handle;
@ -91,6 +93,7 @@ private:
uint8_t m_properties;
attr_value_t m_value;
portMUX_TYPE m_valMux;
uint8_t m_removed;
}; // NimBLEDescriptor

View File

@ -30,7 +30,7 @@
#include "services/gap/ble_svc_gap.h"
#include "services/gatt/ble_svc_gatt.h"
#ifdef ARDUINO_ARCH_ESP32
#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
#include "esp32-hal-bt.h"
#endif
@ -60,6 +60,7 @@ ble_gap_event_listener NimBLEDevice::m_listener;
std::list <NimBLEClient*> NimBLEDevice::m_cList;
#endif
std::list <NimBLEAddress> NimBLEDevice::m_ignoreList;
std::vector<NimBLEAddress> NimBLEDevice::m_whiteList;
NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC;
uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE;
@ -448,6 +449,211 @@ void NimBLEDevice::setScanFilterMode(uint8_t mode) {
m_scanFilterMode = mode;
}
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
/**
* @brief Gets the number of bonded peers stored
*/
/*STATIC*/
int NimBLEDevice::getNumBonds() {
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
int num_peers, rc;
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
if (rc !=0) {
return 0;
}
return num_peers;
}
/**
* @brief Deletes all bonding information.
*/
/*STATIC*/
void NimBLEDevice::deleteAllBonds() {
ble_store_clear();
}
/**
* @brief Deletes a peer bond.
* @param [in] address The address of the peer with which to delete bond info.
* @returns true on success.
*/
/*STATIC*/
bool NimBLEDevice::deleteBond(const NimBLEAddress &address) {
ble_addr_t delAddr;
memcpy(&delAddr.val, address.getNative(),6);
delAddr.type = address.getType();
int rc = ble_gap_unpair(&delAddr);
if (rc != 0) {
return false;
}
return true;
}
/**
* @brief Checks if a peer device is bonded.
* @param [in] address The address to check for bonding.
* @returns true if bonded.
*/
/*STATIC*/
bool NimBLEDevice::isBonded(const NimBLEAddress &address) {
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
int num_peers, rc;
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
if (rc != 0) {
return false;
}
for (int i = 0; i < num_peers; i++) {
NimBLEAddress storedAddr(peer_id_addrs[i]);
if(storedAddr == address) {
return true;
}
}
return false;
}
/**
* @brief Get the address of a bonded peer device by index.
* @param [in] index The index to retrieve the peer address of.
* @returns NimBLEAddress of the found bonded peer or nullptr if not found.
*/
/*STATIC*/
NimBLEAddress NimBLEDevice::getBondedAddress(int index) {
ble_addr_t peer_id_addrs[MYNEWT_VAL(BLE_STORE_MAX_BONDS)];
int num_peers, rc;
rc = ble_store_util_bonded_peers(&peer_id_addrs[0], &num_peers, MYNEWT_VAL(BLE_STORE_MAX_BONDS));
if (rc != 0) {
return nullptr;
}
if (index > num_peers || index < 0) {
return nullptr;
}
return NimBLEAddress(peer_id_addrs[index]);
}
#endif
/**
* @brief Checks if a peer device is whitelisted.
* @param [in] address The address to check for in the whitelist.
* @returns true if the address is in the whitelist.
*/
bool NimBLEDevice::onWhiteList(const NimBLEAddress & address) {
for (auto &it : m_whiteList) {
if (it == address) {
return true;
}
}
return false;
}
/**
* @brief Add a peer address to the whitelist.
* @param [in] address The address to add to the whitelist.
* @returns true if successful.
*/
bool NimBLEDevice::whiteListAdd(const NimBLEAddress & address) {
if (NimBLEDevice::onWhiteList(address)) {
return true;
}
m_whiteList.push_back(address);
std::vector<ble_addr_t> wlVec;
wlVec.reserve(m_whiteList.size());
for (auto &it : m_whiteList) {
ble_addr_t wlAddr;
memcpy(&wlAddr.val, it.getNative(), 6);
wlAddr.type = it.getType();
wlVec.push_back(wlAddr);
}
int rc = ble_gap_wl_set(&wlVec[0], wlVec.size());
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Failed adding to whitelist rc=%d", rc);
return false;
}
return true;
}
/**
* @brief Remove a peer address from the whitelist.
* @param [in] address The address to remove from the whitelist.
* @returns true if successful.
*/
bool NimBLEDevice::whiteListRemove(const NimBLEAddress & address) {
if (!NimBLEDevice::onWhiteList(address)) {
return true;
}
std::vector<ble_addr_t> wlVec;
wlVec.reserve(m_whiteList.size());
for (auto &it : m_whiteList) {
if (it != address) {
ble_addr_t wlAddr;
memcpy(&wlAddr.val, it.getNative(), 6);
wlAddr.type = it.getType();
wlVec.push_back(wlAddr);
}
}
int rc = ble_gap_wl_set(&wlVec[0], wlVec.size());
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Failed removing from whitelist rc=%d", rc);
return false;
}
// Don't remove from the list unless NimBLE returned success
for (auto it = m_whiteList.begin(); it < m_whiteList.end(); ++it) {
if ((*it) == address) {
m_whiteList.erase(it);
break;
}
}
return true;
}
/**
* @brief Gets the count of addresses in the whitelist.
* @returns The number of addresses in the whitelist.
*/
size_t NimBLEDevice::getWhiteListCount() {
return m_whiteList.size();
}
/**
* @brief Gets the address at the vector index.
* @param [in] index The vector index to retrieve the address from.
* @returns the NimBLEAddress at the whitelist index or nullptr if not found.
*/
NimBLEAddress NimBLEDevice::getWhiteListAddress(size_t index) {
if (index > m_whiteList.size()) {
NIMBLE_LOGE(LOG_TAG, "Invalid index; %u", index);
return nullptr;
}
return m_whiteList[index];
}
/**
* @brief Host reset, we pass the message so we don't make calls until resynced.
@ -534,7 +740,7 @@ void NimBLEDevice::setScanFilterMode(uint8_t mode) {
int rc=0;
esp_err_t errRc = ESP_OK;
#ifdef ARDUINO_ARCH_ESP32
#ifdef CONFIG_ENABLE_ARDUINO_DEPENDS
// make sure the linker includes esp32-hal-bt.c so ardruino init doesn't release BLE memory.
btStarted();
#endif
@ -551,8 +757,12 @@ void NimBLEDevice::setScanFilterMode(uint8_t mode) {
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
#ifdef CONFIG_IDF_TARGET_ESP32C3
bt_cfg.bluetooth_mode = ESP_BT_MODE_BLE;
#else
bt_cfg.mode = ESP_BT_MODE_BLE;
bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS;
#endif
bt_cfg.normal_adv_size = m_scanDuplicateSize;
bt_cfg.scan_duplicate_type = m_scanFilterMode;
@ -771,17 +981,23 @@ void NimBLEDevice::setSecurityCallbacks(NimBLESecurityCallbacks* callbacks) {
void NimBLEDevice::setOwnAddrType(uint8_t own_addr_type, bool useNRPA) {
m_own_addr_type = own_addr_type;
switch (own_addr_type) {
#ifdef CONFIG_IDF_TARGET_ESP32
case BLE_OWN_ADDR_PUBLIC:
ble_hs_pvcy_rpa_config(NIMBLE_HOST_DISABLE_PRIVACY);
break;
#endif
case BLE_OWN_ADDR_RANDOM:
setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
#ifdef CONFIG_IDF_TARGET_ESP32
ble_hs_pvcy_rpa_config(useNRPA ? NIMBLE_HOST_ENABLE_NRPA : NIMBLE_HOST_ENABLE_RPA);
#endif
break;
case BLE_OWN_ADDR_RPA_PUBLIC_DEFAULT:
case BLE_OWN_ADDR_RPA_RANDOM_DEFAULT:
setSecurityInitKey(BLE_SM_PAIR_KEY_DIST_ENC | BLE_SM_PAIR_KEY_DIST_ID);
#ifdef CONFIG_IDF_TARGET_ESP32
ble_hs_pvcy_rpa_config(NIMBLE_HOST_ENABLE_RPA);
#endif
break;
}
} // setOwnAddrType

View File

@ -95,6 +95,11 @@ public:
static bool getInitialized();
static NimBLEAddress getAddress();
static std::string toString();
static bool whiteListAdd(const NimBLEAddress & address);
static bool whiteListRemove(const NimBLEAddress & address);
static bool onWhiteList(const NimBLEAddress & address);
static size_t getWhiteListCount();
static NimBLEAddress getWhiteListAddress(size_t index);
#if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
static NimBLEScan* getScan();
@ -142,6 +147,14 @@ public:
static std::list<NimBLEClient*>* getClientList();
#endif
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) || defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
static bool deleteBond(const NimBLEAddress &address);
static int getNumBonds();
static bool isBonded(const NimBLEAddress &address);
static void deleteAllBonds();
static NimBLEAddress getBondedAddress(int index);
#endif
private:
#if defined( CONFIG_BT_NIMBLE_ROLE_CENTRAL)
friend class NimBLEClient;
@ -188,6 +201,7 @@ private:
static uint8_t m_own_addr_type;
static uint16_t m_scanDuplicateSize;
static uint8_t m_scanFilterMode;
static std::vector<NimBLEAddress> m_whiteList;
};

View File

@ -7,17 +7,19 @@
*/
#ifndef MAIN_NIMBLELOG_H_
#define MAIN_NIMBLELOG_H_
#include "sdkconfig.h"
#if defined(CONFIG_BT_ENABLED)
#ifdef ARDUINO_ARCH_ESP32
#include "syscfg/syscfg.h"
#include "modlog/modlog.h"
// If Arduino is being used, strip out the colors and ignore log printing below ui setting.
// Note: because CONFIG_LOG_DEFAULT_LEVEL is set at ERROR in Arduino we must use MODLOG_DFLT(ERROR
// otherwise no messages will be printed above that level.
#ifdef ARDUINO_ARCH_ESP32
#ifndef CORE_DEBUG_LEVEL
#define CORE_DEBUG_LEVEL CONFIG_ARDUHAL_LOG_DEFAULT_LEVEL
#endif
@ -49,11 +51,15 @@
#define NIMBLE_LOGC( tag, format, ... ) MODLOG_DFLT(CRITICAL, "CRIT %s: "#format"\n",tag,##__VA_ARGS__)
#else
#define NIMBLE_LOGE( tag, format, ... ) MODLOG_DFLT(ERROR, "\033[0;31mE %s: "#format"\033[0m\n",tag,##__VA_ARGS__)
#define NIMBLE_LOGW( tag, format, ... ) MODLOG_DFLT(WARN, "\033[0;33mW %s: "#format"\033[0m\n",tag,##__VA_ARGS__)
#define NIMBLE_LOGI( tag, format, ... ) MODLOG_DFLT(INFO, "\033[0;32mI %s: "#format"\033[0m\n",tag,##__VA_ARGS__)
#define NIMBLE_LOGD( tag, format, ... ) MODLOG_DFLT(DEBUG, "D %s: "#format"\n",tag,##__VA_ARGS__)
#define NIMBLE_LOGC( tag, format, ... ) MODLOG_DFLT(CRITICAL, "\033[1;31mCRIT %s: "#format"\033[0m\n",tag,##__VA_ARGS__)
#include "esp_log.h"
#define NIMBLE_LOGE(tag, format, ...) ESP_LOGE(tag, format, ##__VA_ARGS__)
#define NIMBLE_LOGW(tag, format, ...) ESP_LOGW(tag, format, ##__VA_ARGS__)
#define NIMBLE_LOGI(tag, format, ...) ESP_LOGI(tag, format, ##__VA_ARGS__)
#define NIMBLE_LOGD(tag, format, ...) ESP_LOGD(tag, format, ##__VA_ARGS__)
#define NIMBLE_LOGC(tag, format, ...) ESP_LOGE(tag, format, ##__VA_ARGS__)
#endif /*ARDUINO_ARCH_ESP32*/
#endif /*CONFIG_BT_ENABLED*/

View File

@ -55,6 +55,7 @@ static const char* LOG_TAG = "NimBLERemoteCharacteristic";
m_handle = chr->val_handle;
m_defHandle = chr->def_handle;
m_endHandle = 0;
m_charProp = chr->properties;
m_pRemoteService = pRemoteService;
m_notifyCallback = nullptr;
@ -146,31 +147,25 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
const struct ble_gatt_dsc *dsc,
void *arg)
{
NIMBLE_LOGD(LOG_TAG,"Descriptor Discovered >> status: %d handle: %d",
error->status, (error->status == 0) ? dsc->handle : -1);
int rc = error->status;
NIMBLE_LOGD(LOG_TAG, "Descriptor Discovered >> status: %d handle: %d",
rc, (rc == 0) ? dsc->handle : -1);
desc_filter_t *filter = (desc_filter_t*)arg;
const NimBLEUUID *uuid_filter = filter->uuid;
ble_task_data_t *pTaskData = (ble_task_data_t*)filter->task_data;
NimBLERemoteCharacteristic *characteristic = (NimBLERemoteCharacteristic*)pTaskData->pATT;
int rc=0;
if(characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
if (characteristic->getRemoteService()->getClient()->getConnId() != conn_handle){
return 0;
}
switch (error->status) {
switch (rc) {
case 0: {
if(dsc->uuid.u.type == BLE_UUID_TYPE_16 && dsc->uuid.u16.value == uint16_t(0x2803)) {
NIMBLE_LOGD(LOG_TAG,"Descriptor NOT found - end of Characteristic definintion");
rc = BLE_HS_EDONE;
break;
}
if(uuid_filter != nullptr) {
if(ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) {
if (uuid_filter != nullptr) {
if (ble_uuid_cmp(&uuid_filter->getNative()->u, &dsc->uuid.u) != 0) {
return 0;
} else {
NIMBLE_LOGD(LOG_TAG,"Descriptor Found");
rc = BLE_HS_EDONE;
}
}
@ -180,11 +175,10 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
break;
}
default:
rc = error->status;
break;
}
/** If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process.
/* If rc == BLE_HS_EDONE, resume the task with a success error code and stop the discovery process.
* Else if rc == 0, just return 0 to continue the discovery until we get BLE_HS_EDONE.
* If we get any other error code tell the application to abort by returning non-zero in the rc.
*/
@ -202,6 +196,38 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
}
/**
* @brief callback from NimBLE when the next characteristic of the service is discovered.
*/
int NimBLERemoteCharacteristic::nextCharCB(uint16_t conn_handle,
const struct ble_gatt_error *error,
const struct ble_gatt_chr *chr, void *arg)
{
int rc = error->status;
NIMBLE_LOGD(LOG_TAG, "Next Characteristic >> status: %d handle: %d",
rc, (rc == 0) ? chr->val_handle : -1);
ble_task_data_t *pTaskData = (ble_task_data_t*)arg;
NimBLERemoteCharacteristic *pChar = (NimBLERemoteCharacteristic*)pTaskData->pATT;
if (pChar->getRemoteService()->getClient()->getConnId() != conn_handle) {
return 0;
}
if (rc == 0) {
pChar->m_endHandle = chr->def_handle - 1;
rc = BLE_HS_EDONE;
} else if (rc == BLE_HS_EDONE) {
pChar->m_endHandle = pChar->getRemoteService()->getEndHandle();
} else {
pTaskData->rc = rc;
}
xTaskNotifyGive(pTaskData->task);
return rc;
}
/**
* @brief Populate the descriptors (if any) for this characteristic.
* @param [in] the end handle of the characteristic, or the service, whichever comes first.
@ -209,35 +235,57 @@ int NimBLERemoteCharacteristic::descriptorDiscCB(uint16_t conn_handle,
bool NimBLERemoteCharacteristic::retrieveDescriptors(const NimBLEUUID *uuid_filter) {
NIMBLE_LOGD(LOG_TAG, ">> retrieveDescriptors() for characteristic: %s", getUUID().toString().c_str());
uint16_t endHandle = getRemoteService()->getEndHandle(this);
if(m_handle >= endHandle) {
return false;
// If this is the last handle then there are no descriptors
if (m_handle == getRemoteService()->getEndHandle()) {
return true;
}
int rc = 0;
ble_task_data_t taskData = {this, xTaskGetCurrentTaskHandle(), 0, nullptr};
// If we don't know the end handle of this characteristic retrieve the next one in the service
// The end handle is the next characteristic definition handle -1.
if (m_endHandle == 0) {
rc = ble_gattc_disc_all_chrs(getRemoteService()->getClient()->getConnId(),
m_handle,
getRemoteService()->getEndHandle(),
NimBLERemoteCharacteristic::nextCharCB,
&taskData);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Error getting end handle rc=%d", rc);
return false;
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if (taskData.rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Could not retrieve end handle rc=%d", taskData.rc);
return false;
}
}
desc_filter_t filter = {uuid_filter, &taskData};
rc = ble_gattc_disc_all_dscs(getRemoteService()->getClient()->getConnId(),
m_handle,
endHandle,
m_endHandle,
NimBLERemoteCharacteristic::descriptorDiscCB,
&filter);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_dscs: rc=%d %s", rc, NimBLEUtils::returnCodeToString(rc));
return false;
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if(taskData.rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gattc_disc_all_chrs: startHandle:%d endHandle:%d taskData.rc=%d %s", m_handle, endHandle, taskData.rc, NimBLEUtils::returnCodeToString(0x0100+taskData.rc));
return false;
if (taskData.rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Failed to retrieve descriptors; startHandle:%d endHandle:%d taskData.rc=%d",
m_handle, m_endHandle, taskData.rc);
}
return true;
NIMBLE_LOGD(LOG_TAG, "<< retrieveDescriptors(): Found %d descriptors.", m_descriptorVector.size());
return (taskData.rc == 0);
} // retrieveDescriptors
@ -664,7 +712,7 @@ std::string NimBLERemoteCharacteristic::toString() {
* @return false if not connected or cant perform write for some reason.
*/
bool NimBLERemoteCharacteristic::writeValue(const std::string &newValue, bool response) {
return writeValue((uint8_t*)newValue.c_str(), strlen(newValue.c_str()), response);
return writeValue((uint8_t*)newValue.c_str(), newValue.length(), response);
} // writeValue

View File

@ -148,12 +148,15 @@ private:
static int descriptorDiscCB(uint16_t conn_handle, const struct ble_gatt_error *error,
uint16_t chr_val_handle, const struct ble_gatt_dsc *dsc,
void *arg);
static int nextCharCB(uint16_t conn_handle, const struct ble_gatt_error *error,
const struct ble_gatt_chr *chr, void *arg);
// Private properties
NimBLEUUID m_uuid;
uint8_t m_charProp;
uint16_t m_handle;
uint16_t m_defHandle;
uint16_t m_endHandle;
NimBLERemoteService* m_pRemoteService;
std::string m_value;
notify_callback m_notifyCallback;

View File

@ -223,6 +223,20 @@ bool NimBLERemoteService::retrieveCharacteristics(const NimBLEUUID *uuid_filter)
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
if(taskData.rc == 0){
if (uuid_filter == nullptr) {
if (m_characteristicVector.size() > 1) {
for (auto it = m_characteristicVector.begin(); it != m_characteristicVector.end(); ++it ) {
auto nx = std::next(it, 1);
if (nx == m_characteristicVector.end()) {
break;
}
(*it)->m_endHandle = (*nx)->m_defHandle - 1;
}
}
m_characteristicVector.back()->m_endHandle = getEndHandle();
}
NIMBLE_LOGD(LOG_TAG, "<< retrieveCharacteristics()");
return true;
}
@ -249,23 +263,6 @@ uint16_t NimBLERemoteService::getEndHandle() {
return m_endHandle;
} // getEndHandle
/**
* @brief Get the end handle of specified NimBLERemoteCharacteristic.
*/
uint16_t NimBLERemoteService::getEndHandle(NimBLERemoteCharacteristic *pCharacteristic) {
uint16_t endHandle = m_endHandle;
for(auto &it: m_characteristicVector) {
uint16_t defHandle = it->getDefHandle() - 1;
if(defHandle > pCharacteristic->getDefHandle() && endHandle > defHandle) {
endHandle = defHandle;
}
}
return endHandle;
} // getEndHandle
/**
* @brief Get the service start handle.

View File

@ -70,7 +70,6 @@ private:
uint16_t getStartHandle();
uint16_t getEndHandle();
uint16_t getEndHandle(NimBLERemoteCharacteristic *pCharacteristic);
void releaseSemaphores();
// Properties

View File

@ -110,7 +110,7 @@ NimBLEScan::~NimBLEScan() {
advertisedDevice->m_timestamp = time(nullptr);
advertisedDevice->setRSSI(event->disc.rssi);
advertisedDevice->setPayload(event->disc.data, event->disc.length_data,
advertisedDevice->setPayload(event->disc.data, event->disc.length_data,
event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP);
if (pScan->m_pAdvertisedDeviceCallbacks) {
@ -128,7 +128,7 @@ NimBLEScan::~NimBLEScan() {
advertisedDevice->m_callbackSent = true;
pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
}
// If not storing results and we have invoked the callback, delete the device.
// If not storing results and we have invoked the callback, delete the device.
if(pScan->m_maxResults == 0 && advertisedDevice->m_callbackSent) {
pScan->erase(advertisedAddress);
}
@ -316,6 +316,8 @@ bool NimBLEScan::start(uint32_t duration, void (*scanCompleteCB)(NimBLEScanResul
break;
case BLE_HS_EALREADY:
// Clear the cache if already scanning in case an advertiser was missed.
clearDuplicateCache();
break;
case BLE_HS_EBUSY:
@ -398,6 +400,16 @@ bool NimBLEScan::stop() {
} // stop
/**
* @brief Clears the duplicate scan filter cache.
*/
void NimBLEScan::clearDuplicateCache() {
#ifdef CONFIG_IDF_TARGET_ESP32 // Not available for ESP32C3
esp_ble_scan_dupilcate_list_flush();
#endif
}
/**
* @brief Delete peer device from the scan results vector.
* @param [in] address The address of the device to delete from the results.
@ -453,6 +465,7 @@ void NimBLEScan::clearResults() {
delete it;
}
m_scanResults.m_advertisedDevicesVector.clear();
clearDuplicateCache();
}

View File

@ -70,6 +70,7 @@ public:
void setDuplicateFilter(bool enabled);
void setLimitedOnly(bool enabled);
void setFilterPolicy(uint8_t filter);
void clearDuplicateCache();
bool stop();
void clearResults();
NimBLEScanResults getResults();

View File

@ -37,6 +37,7 @@ static NimBLEServerCallbacks defaultCallbacks;
* the NimBLEDevice class.
*/
NimBLEServer::NimBLEServer() {
memset(m_indWait, BLE_HS_CONN_HANDLE_NONE, sizeof(m_indWait));
// m_svcChgChrHdl = 0xffff; // Future Use
m_pServerCallbacks = &defaultCallbacks;
m_gattsStarted = false;
@ -90,12 +91,7 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
NimBLEService* pService = new NimBLEService(uuid, numHandles, this);
m_svcVec.push_back(pService); // Save a reference to this service being on this server.
if(m_gattsStarted) {
ble_svc_gatt_changed(0x0001, 0xffff);
m_svcChanged = true;
resetGATT();
}
serviceChanged();
NIMBLE_LOGD(LOG_TAG, "<< createService");
return pService;
@ -156,6 +152,18 @@ NimBLEAdvertising* NimBLEServer::getAdvertising() {
} // getAdvertising
/**
* @brief Sends a service changed notification and resets the GATT server.
*/
void NimBLEServer::serviceChanged() {
if(m_gattsStarted) {
m_svcChanged = true;
ble_svc_gatt_changed(0x0001, 0xffff);
resetGATT();
}
}
/**
* @brief Start the GATT server. Required to be called after setup of all
* services and characteristics / descriptors for the NimBLE host to register them.
@ -253,6 +261,63 @@ size_t NimBLEServer::getConnectedCount() {
} // getConnectedCount
/**
* @brief Get the vector of the connected client ID's.
*/
std::vector<uint16_t> NimBLEServer::getPeerDevices() {
return m_connectedPeersVec;
} // getPeerDevices
/**
* @brief Get the connection information of a connected peer by vector index.
* @param [in] index The vector index of the peer.
*/
NimBLEConnInfo NimBLEServer::getPeerInfo(size_t index) {
if (index >= m_connectedPeersVec.size()) {
NIMBLE_LOGE(LOG_TAG, "No peer at index %u", index);
return NimBLEConnInfo();
}
return getPeerIDInfo(m_connectedPeersVec[index]);
} // getPeerInfo
/**
* @brief Get the connection information of a connected peer by address.
* @param [in] address The address of the peer.
*/
NimBLEConnInfo NimBLEServer::getPeerInfo(const NimBLEAddress& address) {
ble_addr_t peerAddr;
memcpy(&peerAddr.val, address.getNative(),6);
peerAddr.type = address.getType();
NimBLEConnInfo peerInfo;
int rc = ble_gap_conn_find_by_addr(&peerAddr, &peerInfo.m_desc);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
}
return peerInfo;
} // getPeerInfo
/**
* @brief Get the connection information of a connected peer by connection ID.
* @param [in] id The connection id of the peer.
*/
NimBLEConnInfo NimBLEServer::getPeerIDInfo(uint16_t id) {
NimBLEConnInfo peerInfo;
int rc = ble_gap_conn_find(id, &peerInfo.m_desc);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Peer info not found");
}
return peerInfo;
} // getPeerIDInfo
/**
* @brief Handle a GATT Server Event.
*
@ -280,7 +345,9 @@ size_t NimBLEServer::getConnectedCount() {
server->m_connectedPeersVec.push_back(event->connect.conn_handle);
rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
assert(rc == 0);
if (rc != 0) {
return 0;
}
server->m_pServerCallbacks->onConnect(server);
server->m_pServerCallbacks->onConnect(server, &desc);
@ -335,7 +402,9 @@ size_t NimBLEServer::getConnectedCount() {
(it->getProperties() & BLE_GATT_CHR_F_READ_ENC))
{
rc = ble_gap_conn_find(event->subscribe.conn_handle, &desc);
assert(rc == 0);
if (rc != 0) {
break;
}
if(!desc.sec_state.encrypted) {
NimBLEDevice::startSecurity(event->subscribe.conn_handle);
@ -354,22 +423,54 @@ size_t NimBLEServer::getConnectedCount() {
NIMBLE_LOGI(LOG_TAG, "mtu update event; conn_handle=%d mtu=%d",
event->mtu.conn_handle,
event->mtu.value);
rc = ble_gap_conn_find(event->mtu.conn_handle, &desc);
if (rc != 0) {
return 0;
}
server->m_pServerCallbacks->onMTUChange(event->mtu.value, &desc);
return 0;
} // BLE_GAP_EVENT_MTU
case BLE_GAP_EVENT_NOTIFY_TX: {
if(event->notify_tx.indication && event->notify_tx.status != 0) {
for(auto &it : server->m_notifyChrVec) {
if(it->getHandle() == event->notify_tx.attr_handle) {
if(it->m_pTaskData != nullptr) {
it->m_pTaskData->rc = event->notify_tx.status;
xTaskNotifyGive(it->m_pTaskData->task);
}
break;
}
NimBLECharacteristic *pChar = nullptr;
for(auto &it : server->m_notifyChrVec) {
if(it->getHandle() == event->notify_tx.attr_handle) {
pChar = it;
}
}
if(pChar == nullptr) {
return 0;
}
NimBLECharacteristicCallbacks::Status statusRC;
if(event->notify_tx.indication) {
if(event->notify_tx.status != 0) {
if(event->notify_tx.status == BLE_HS_EDONE) {
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_INDICATE;
} else if(rc == BLE_HS_ETIMEOUT) {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_TIMEOUT;
} else {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_INDICATE_FAILURE;
}
} else {
return 0;
}
server->clearIndicateWait(event->notify_tx.conn_handle);
} else {
if(event->notify_tx.status == 0) {
statusRC = NimBLECharacteristicCallbacks::Status::SUCCESS_NOTIFY;
} else {
statusRC = NimBLECharacteristicCallbacks::Status::ERROR_GATT;
}
}
pChar->m_pCallbacks->onStatus(pChar, statusRC, event->notify_tx.status);
return 0;
} // BLE_GAP_EVENT_NOTIFY_TX
@ -392,7 +493,10 @@ size_t NimBLEServer::getConnectedCount() {
/* Delete the old bond. */
rc = ble_gap_conn_find(event->repeat_pairing.conn_handle, &desc);
assert(rc == 0);
if (rc != 0){
return BLE_GAP_REPEAT_PAIRING_IGNORE;
}
ble_store_util_delete_peer(&desc.peer_id_addr);
/* Return BLE_GAP_REPEAT_PAIRING_RETRY to indicate that the host should
@ -533,7 +637,7 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
if(service->m_removed > 0) {
if(deleteSvc) {
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ++it) {
if ((*it)->getUUID() == service->getUUID()) {
if ((*it) == service) {
delete *it;
m_svcVec.erase(it);
break;
@ -549,32 +653,35 @@ void NimBLEServer::removeService(NimBLEService* service, bool deleteSvc) {
return;
}
service->m_removed = deleteSvc ? 2 : 1;
m_svcChanged = true;
ble_svc_gatt_changed(0x0001, 0xffff);
resetGATT();
service->m_removed = deleteSvc ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
serviceChanged();
NimBLEDevice::getAdvertising()->removeServiceUUID(service->getUUID());
}
/**
* @brief Adds a service which was already created, but removed from availability.
* @brief Adds a service which was either already created but removed from availability,\n
* or created and later added to services list.
* @param [in] service The service object to add.
* @note If it is desired to advertise the service it must be added by
* calling NimBLEAdvertising::addServiceUUID.
*/
void NimBLEServer::addService(NimBLEService* service) {
// If adding a service that was not removed just return.
// Check that a service with the supplied UUID does not already exist.
if(getServiceByUUID(service->getUUID()) != nullptr) {
NIMBLE_LOGW(LOG_TAG, "Warning creating a duplicate service UUID: %s",
std::string(service->getUUID()).c_str());
}
// If adding a service that was not removed add it and return.
// Else reset GATT and send service changed notification.
if(service->m_removed == 0) {
m_svcVec.push_back(service);
return;
}
service->m_removed = 0;
m_svcChanged = true;
ble_svc_gatt_changed(0x0001, 0xffff);
resetGATT();
serviceChanged();
}
@ -593,7 +700,7 @@ void NimBLEServer::resetGATT() {
for(auto it = m_svcVec.begin(); it != m_svcVec.end(); ) {
if ((*it)->m_removed > 0) {
if ((*it)->m_removed == 2) {
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
delete *it;
it = m_svcVec.erase(it);
} else {
@ -668,6 +775,27 @@ void NimBLEServer::updateConnParams(uint16_t conn_handle,
}// updateConnParams
bool NimBLEServer::setIndicateWait(uint16_t conn_handle) {
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
if(m_indWait[i] == conn_handle) {
return false;
}
}
return true;
}
void NimBLEServer::clearIndicateWait(uint16_t conn_handle) {
for(auto i = 0; i < CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
if(m_indWait[i] == conn_handle) {
m_indWait[i] = BLE_HS_CONN_HANDLE_NONE;
return;
}
}
}
/** Default callback handlers */
void NimBLEServerCallbacks::onConnect(NimBLEServer* pServer) {
@ -688,6 +816,10 @@ void NimBLEServerCallbacks::onDisconnect(NimBLEServer* pServer, ble_gap_conn_des
NIMBLE_LOGD("NimBLEServerCallbacks", "onDisconnect(): Default");
} // onDisconnect
void NimBLEServerCallbacks::onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc) {
NIMBLE_LOGD("NimBLEServerCallbacks", "onMTUChange(): Default");
} // onMTUChange
uint32_t NimBLEServerCallbacks::onPassKeyRequest(){
NIMBLE_LOGD("NimBLEServerCallbacks", "onPassKeyRequest: default: 123456");
return 123456;

View File

@ -20,11 +20,15 @@
#include "nimconfig.h"
#if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#define NIMBLE_ATT_REMOVE_HIDE 1
#define NIMBLE_ATT_REMOVE_DELETE 2
#include "NimBLEUtils.h"
#include "NimBLEAddress.h"
#include "NimBLEAdvertising.h"
#include "NimBLEService.h"
#include "NimBLESecurity.h"
#include "NimBLEConnInfo.h"
class NimBLEService;
@ -58,13 +62,17 @@ public:
uint16_t minInterval, uint16_t maxInterval,
uint16_t latency, uint16_t timeout);
uint16_t getPeerMTU(uint16_t conn_id);
// std::vector<uint16_t> getPeerDevices();
std::vector<uint16_t> getPeerDevices();
NimBLEConnInfo getPeerInfo(size_t index);
NimBLEConnInfo getPeerInfo(const NimBLEAddress& address);
NimBLEConnInfo getPeerIDInfo(uint16_t id);
void advertiseOnDisconnect(bool);
private:
NimBLEServer();
~NimBLEServer();
friend class NimBLECharacteristic;
friend class NimBLEService;
friend class NimBLEDevice;
friend class NimBLEAdvertising;
@ -73,6 +81,7 @@ private:
bool m_svcChanged;
NimBLEServerCallbacks* m_pServerCallbacks;
bool m_deleteCallbacks;
uint16_t m_indWait[CONFIG_BT_NIMBLE_MAX_CONNECTIONS];
std::vector<uint16_t> m_connectedPeersVec;
// uint16_t m_svcChgChrHdl; // Future use
@ -81,7 +90,10 @@ private:
std::vector<NimBLECharacteristic*> m_notifyChrVec;
static int handleGapEvent(struct ble_gap_event *event, void *arg);
void serviceChanged();
void resetGATT();
bool setIndicateWait(uint16_t conn_handle);
void clearIndicateWait(uint16_t conn_handle);
}; // NimBLEServer
@ -124,6 +136,14 @@ public:
*/
virtual void onDisconnect(NimBLEServer* pServer, ble_gap_conn_desc* desc);
/**
* @brief Called when the connection MTU changes.
* @param [in] MTU The new MTU value.
* @param [in] desc A pointer to the connection description structure containig information
* about the connection.
*/
virtual void onMTUChange(uint16_t MTU, ble_gap_conn_desc* desc);
/**
* @brief Called when a client requests a passkey for pairing.
* @return The passkey to be sent to the client.

View File

@ -35,7 +35,7 @@ static const char* LOG_TAG = "NimBLEService"; // Tag for logging.
* @brief Construct an instance of the NimBLEService
* @param [in] uuid The UUID of the service.
* @param [in] numHandles The maximum number of handles associated with the service.
* @param [in] a pointer to the server instance that this service belongs to.
* @param [in] pServer A pointer to the server instance that this service belongs to.
*/
NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer)
: NimBLEService(NimBLEUUID(uuid), numHandles, pServer) {
@ -46,7 +46,7 @@ NimBLEService::NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer
* @brief Construct an instance of the BLEService
* @param [in] uuid The UUID of the service.
* @param [in] numHandles The maximum number of handles associated with the service.
* @param [in] a pointer to the server instance that this service belongs to.
* @param [in] pServer A pointer to the server instance that this service belongs to.
*/
NimBLEService::NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer) {
m_uuid = uuid;
@ -118,7 +118,12 @@ NimBLEUUID NimBLEService::getUUID() {
*/
bool NimBLEService::start() {
NIMBLE_LOGD(LOG_TAG, ">> start(): Starting service: %s", toString().c_str());
int rc = 0;
// Rebuild the service definition if the server attributes have changed.
if(getServer()->m_svcChanged && m_pSvcDef != nullptr) {
delete(m_pSvcDef);
m_pSvcDef = nullptr;
}
if(m_pSvcDef == nullptr) {
// Nimble requires an array of services to be sent to the api
@ -132,8 +137,23 @@ bool NimBLEService::start() {
svc[0].uuid = &m_uuid.getNative()->u;
svc[0].includes = NULL;
size_t numChrs = m_chrVec.size();
int removedCount = 0;
for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ) {
if ((*it)->m_removed > 0) {
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
delete *it;
it = m_chrVec.erase(it);
} else {
++removedCount;
++it;
}
continue;
}
++it;
}
size_t numChrs = m_chrVec.size() - removedCount;
NIMBLE_LOGD(LOG_TAG,"Adding %d characteristics for service %s", numChrs, toString().c_str());
if(!numChrs){
@ -142,40 +162,60 @@ bool NimBLEService::start() {
// Nimble requires the last characteristic to have it's uuid = 0 to indicate the end
// of the characteristics for the service. We create 1 extra and set it to null
// for this purpose.
pChr_a = new ble_gatt_chr_def[numChrs+1];
NimBLECharacteristic* pCharacteristic = *m_chrVec.begin();
pChr_a = new ble_gatt_chr_def[numChrs + 1];
uint8_t i = 0;
for(auto chr_it = m_chrVec.begin(); chr_it != m_chrVec.end(); ++chr_it) {
if((*chr_it)->m_removed > 0) {
continue;
}
for(uint8_t i=0; i < numChrs;) {
uint8_t numDscs = pCharacteristic->m_dscVec.size();
removedCount = 0;
for(auto it = (*chr_it)->m_dscVec.begin(); it != (*chr_it)->m_dscVec.end(); ) {
if ((*it)->m_removed > 0) {
if ((*it)->m_removed == NIMBLE_ATT_REMOVE_DELETE) {
delete *it;
it = (*chr_it)->m_dscVec.erase(it);
} else {
++removedCount;
++it;
}
continue;
}
++it;
}
size_t numDscs = (*chr_it)->m_dscVec.size() - removedCount;
if(!numDscs){
pChr_a[i].descriptors = NULL;
} else {
// Must have last descriptor uuid = 0 so we have to create 1 extra
pDsc_a = new ble_gatt_dsc_def[numDscs+1];
NimBLEDescriptor* pDescriptor = *pCharacteristic->m_dscVec.begin();
for(uint8_t d=0; d < numDscs;) {
pDsc_a[d].uuid = &pDescriptor->m_uuid.getNative()->u;
pDsc_a[d].att_flags = pDescriptor->m_properties;
uint8_t d = 0;
for(auto dsc_it = (*chr_it)->m_dscVec.begin(); dsc_it != (*chr_it)->m_dscVec.end(); ++dsc_it ) {
if((*dsc_it)->m_removed > 0) {
continue;
}
pDsc_a[d].uuid = &(*dsc_it)->m_uuid.getNative()->u;
pDsc_a[d].att_flags = (*dsc_it)->m_properties;
pDsc_a[d].min_key_size = 0;
pDsc_a[d].access_cb = NimBLEDescriptor::handleGapEvent;
pDsc_a[d].arg = pDescriptor;
d++;
pDescriptor = *(pCharacteristic->m_dscVec.begin() + d);
pDsc_a[d].arg = (*dsc_it);
++d;
}
pDsc_a[numDscs].uuid = NULL;
pChr_a[i].descriptors = pDsc_a;
}
pChr_a[i].uuid = &pCharacteristic->m_uuid.getNative()->u;
pChr_a[i].uuid = &(*chr_it)->m_uuid.getNative()->u;
pChr_a[i].access_cb = NimBLECharacteristic::handleGapEvent;
pChr_a[i].arg = pCharacteristic;
pChr_a[i].flags = pCharacteristic->m_properties;
pChr_a[i].arg = (*chr_it);
pChr_a[i].flags = (*chr_it)->m_properties;
pChr_a[i].min_key_size = 0;
pChr_a[i].val_handle = &pCharacteristic->m_handle;
i++;
pCharacteristic = *(m_chrVec.begin() + i);
pChr_a[i].val_handle = &(*chr_it)->m_handle;
++i;
}
pChr_a[numChrs].uuid = NULL;
@ -187,7 +227,7 @@ bool NimBLEService::start() {
m_pSvcDef = svc;
}
rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)m_pSvcDef);
int rc = ble_gatts_count_cfg((const ble_gatt_svc_def*)m_pSvcDef);
if (rc != 0) {
NIMBLE_LOGE(LOG_TAG, "ble_gatts_count_cfg failed, rc= %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
return false;
@ -239,13 +279,64 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid
std::string(uuid).c_str());
}
// Remember this characteristic in our vector of characteristics.
m_chrVec.push_back(pCharacteristic);
addCharacteristic(pCharacteristic);
return pCharacteristic;
} // createCharacteristic
/**
* @brief Add a characteristic to the service.
* @param[in] pCharacteristic A pointer to the characteristic instance to add to the service.
*/
void NimBLEService::addCharacteristic(NimBLECharacteristic* pCharacteristic) {
bool foundRemoved = false;
if(pCharacteristic->m_removed > 0) {
for(auto& it : m_chrVec) {
if(it == pCharacteristic) {
foundRemoved = true;
pCharacteristic->m_removed = 0;
}
}
}
if(!foundRemoved) {
m_chrVec.push_back(pCharacteristic);
}
pCharacteristic->setService(this);
getServer()->serviceChanged();
} // addCharacteristic
/**
* @brief Remove a characteristic from the service.
* @param[in] pCharacteristic A pointer to the characteristic instance to remove from the service.
* @param[in] deleteChr If true it will delete the characteristic instance and free it's resources.
*/
void NimBLEService::removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr) {
// Check if the characteristic was already removed and if so, check if this
// is being called to delete the object and do so if requested.
// Otherwise, ignore the call and return.
if(pCharacteristic->m_removed > 0) {
if(deleteChr) {
for(auto it = m_chrVec.begin(); it != m_chrVec.end(); ++it) {
if ((*it) == pCharacteristic) {
m_chrVec.erase(it);
delete *it;
break;
}
}
}
return;
}
pCharacteristic->m_removed = deleteChr ? NIMBLE_ATT_REMOVE_DELETE : NIMBLE_ATT_REMOVE_HIDE;
getServer()->serviceChanged();
} // removeCharacteristic
/**
* @brief Get a pointer to the characteristic object with the specified UUID.
* @param [in] uuid The UUID of the characteristic.

View File

@ -36,6 +36,10 @@ class NimBLECharacteristic;
class NimBLEService {
public:
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
~NimBLEService();
NimBLEServer* getServer();
NimBLEUUID getUUID();
@ -55,6 +59,8 @@ public:
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE);
void addCharacteristic(NimBLECharacteristic* pCharacteristic);
void removeCharacteristic(NimBLECharacteristic* pCharacteristic, bool deleteChr = false);
NimBLECharacteristic* getCharacteristic(const char* uuid, uint16_t instanceId = 0);
NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId = 0);
NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle);
@ -65,9 +71,6 @@ public:
private:
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
NimBLEService(const NimBLEUUID &uuid, uint16_t numHandles, NimBLEServer* pServer);
~NimBLEService();
friend class NimBLEServer;
friend class NimBLEDevice;

View File

@ -277,10 +277,6 @@ std::string NimBLEUUID::toString() const {
*/
bool NimBLEUUID::operator ==(const NimBLEUUID & rhs) const {
if(m_valueSet && rhs.m_valueSet) {
NIMBLE_LOGD(LOG_TAG,"Comparing UUIDs; type %u to %u; UUID %s to %s",
m_uuid.u.type, rhs.m_uuid.u.type,
this->toString().c_str(), rhs.toString().c_str());
if(m_uuid.u.type != rhs.m_uuid.u.type) {
uint8_t uuidBase[16] = {
0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,

View File

@ -19,13 +19,6 @@
* under the License.
*/
/*
* This file has been modified by Ryan Powell, aka h2zero.
* The modifications are for the purpose of improving performance and support
* for Esprssif versions used by the ardruino-esp32 core that are less current
* than the esp-idf releases.
*/
#include <assert.h>
#include "sysinit/sysinit.h"
#include "nimble/hci_common.h"
@ -44,6 +37,8 @@
#endif
#define NIMBLE_VHCI_TIMEOUT_MS 2000
#define BLE_HCI_EVENT_HDR_LEN (2)
#define BLE_HCI_CMD_HDR_LEN (3)
static ble_hci_trans_rx_cmd_fn *ble_hci_rx_cmd_hs_cb;
static void *ble_hci_rx_cmd_hs_arg;
@ -276,7 +271,9 @@ void ble_hci_trans_buf_free(uint8_t *buf)
*/
int ble_hci_trans_set_acl_free_cb(os_mempool_put_fn *cb, void *arg)
{
return BLE_ERR_UNSUPPORTED;
ble_hci_acl_pool.mpe_put_cb = cb;
ble_hci_acl_pool.mpe_put_arg = arg;
return 0;
}
int ble_hci_trans_reset(void)
@ -313,6 +310,7 @@ static struct os_mbuf *ble_hci_trans_acl_buf_alloc(void)
static void ble_hci_rx_acl(uint8_t *data, uint16_t len)
{
struct os_mbuf *m;
int rc;
int sr;
if (len < BLE_HCI_DATA_HDR_SZ || len > MYNEWT_VAL(BLE_ACL_BUF_SIZE)) {
return;
@ -321,9 +319,11 @@ static void ble_hci_rx_acl(uint8_t *data, uint16_t len)
m = ble_hci_trans_acl_buf_alloc();
if (!m) {
ESP_LOGE(TAG, "%s failed to allocate ACL buffers; increase ACL_BUF_COUNT", __func__);
return;
}
if (os_mbuf_append(m, data, len)) {
if ((rc = os_mbuf_append(m, data, len)) != 0) {
ESP_LOGE(TAG, "%s failed to os_mbuf_append; rc = %d", __func__, rc);
os_mbuf_free_chain(m);
return;
}

View File

@ -25,6 +25,10 @@
#define MYNEWT_VAL_MSYS_1_BLOCK_SIZE (292)
#endif
#ifndef MYNEWT_VAL_MSYS_1_SANITY_MIN_COUNT
#define MYNEWT_VAL_MSYS_1_SANITY_MIN_COUNT (0)
#endif
#ifndef MYNEWT_VAL_MSYS_2_BLOCK_COUNT
#define MYNEWT_VAL_MSYS_2_BLOCK_COUNT (0)
#endif
@ -43,11 +47,15 @@
/*** nimble */
#ifndef MYNEWT_VAL_BLE_EXT_ADV
#define MYNEWT_VAL_BLE_EXT_ADV (0)
#define MYNEWT_VAL_BLE_EXT_ADV (CONFIG_BT_NIMBLE_EXT_ADV)
#endif
#ifndef MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE
#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (31)
#ifdef CONFIG_BT_NIMBLE_EXT_ADV
#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (CONFIG_BT_NIMBLE_MAX_EXT_ADV_DATA_LEN)
#else
#define MYNEWT_VAL_BLE_EXT_ADV_MAX_SIZE (0)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_MAX_CONNECTIONS
@ -55,12 +63,20 @@
#endif
#ifndef MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES
#ifdef CONFIG_BT_NIMBLE_EXT_ADV
#define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (CONFIG_BT_NIMBLE_MAX_EXT_ADV_INSTANCES)
#else
#define MYNEWT_VAL_BLE_MULTI_ADV_INSTANCES (0)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS
#ifdef CONFIG_BT_NIMBLE_ENABLE_PERIODIC_ADV
#define MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS (CONFIG_BT_NIMBLE_MAX_PERIODIC_SYNCS)
#else
#define MYNEWT_VAL_BLE_MAX_PERIODIC_SYNCS (0)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_ROLE_BROADCASTER
#ifdef CONFIG_BT_NIMBLE_ROLE_BROADCASTER
@ -267,9 +283,25 @@
#define MYNEWT_VAL_BLE_ATT_PREFERRED_MTU CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU
#endif
#ifndef MYNEWT_VAL_BLE_HS_LOG_LVL
#define MYNEWT_VAL_BLE_HS_LOG_LVL CONFIG_BT_NIMBLE_LOG_LEVEL
#endif
#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV
#ifdef CONFIG_BT_NIMBLE_EXT_ADV
#define MYNEWT_VAL_BLE_PERIODIC_ADV (CONFIG_BT_NIMBLE_ENABLE_PERIODIC_ADV)
#else
#define MYNEWT_VAL_BLE_PERIODIC_ADV (0)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER
#define MYNEWT_VAL_BLE_PERIODIC_ADV_SYNC_TRANSFER (0)
#endif
#ifndef MYNEWT_VAL_BLE_VERSION
#define MYNEWT_VAL_BLE_VERSION (50)
#endif
#ifndef MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO
#define MYNEWT_VAL_BLE_ATT_SVR_FIND_INFO (1)
@ -479,6 +511,18 @@
#define MYNEWT_VAL_BLE_HS_REQUIRE_OS (1)
#endif
#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN
#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN (1)
#endif
#ifndef MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT
#define MYNEWT_VAL_BLE_HS_STOP_ON_SHUTDOWN_TIMEOUT CONFIG_BT_NIMBLE_HS_STOP_TIMEOUT_MS
#endif
#ifndef MYNEWT_VAL_BLE_HS_SYSINIT_STAGE
#define MYNEWT_VAL_BLE_HS_SYSINIT_STAGE (200)
#endif
#ifndef MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM
#define MYNEWT_VAL_BLE_L2CAP_COC_MAX_NUM CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM
#endif
@ -547,8 +591,12 @@
#define MYNEWT_VAL_BLE_MONITOR_UART_DEV ("uart0")
#endif
#ifndef MYNEWT_VAL_BLE_HOST_BASED_PRIVACY
#if CONFIG_IDF_TARGET_ESP32
#define MYNEWT_VAL_BLE_HOST_BASED_PRIVACY (1)
#else
#ifndef MYNEWT_VAL_BLE_HOST_BASED_PRIVACY
#define MYNEWT_VAL_BLE_HOST_BASED_PRIVACY (CONFIG_BT_NIMBLE_HOST_BASED_PRIVACY)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_RPA_TIMEOUT
@ -615,6 +663,27 @@
#define MYNEWT_VAL_BLE_STORE_MAX_CCCDS CONFIG_BT_NIMBLE_MAX_CCCDS
#endif
/*** @apache-mynewt-nimble/nimble/host/mesh */
#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_ACCESS_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_ACCESS_LOG_MOD (10)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT
#define MYNEWT_VAL_BLE_MESH_ADV_BUF_COUNT (20)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_ADV_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_ADV_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_ADV_LOG_MOD (11)
#endif
#ifndef MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST
#ifdef CONFIG_BT_NIMBLE_NVS_PERSIST
#define MYNEWT_VAL_BLE_STORE_CONFIG_PERSIST (1)
@ -645,6 +714,9 @@
#define MYNEWT_VAL_BLE_MESH_ADV_TASK_PRIO (9)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT
#define MYNEWT_VAL_BLE_MESH_APP_KEY_COUNT (4)
#endif
/*** @apache-mynewt-nimble/nimble/host/mesh */
/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */
@ -758,6 +830,14 @@
#endif
#endif
#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_FRIEND_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_FRIEND_LOG_MOD (14)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT
#define MYNEWT_VAL_BLE_MESH_FRIEND_LPN_COUNT (2)
#endif
@ -802,6 +882,14 @@
#define MYNEWT_VAL_BLE_MESH_LABEL_COUNT (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_LOG_MOD (9)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER
#ifdef CONFIG_BT_NIMBLE_MESH_LOW_POWER
#define MYNEWT_VAL_BLE_MESH_LOW_POWER (1)
@ -810,6 +898,14 @@
#endif
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_LOW_POWER_LOG_MOD (15)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_LPN_AUTO
#define MYNEWT_VAL_BLE_MESH_LPN_AUTO (1)
#endif
@ -858,6 +954,10 @@
#define MYNEWT_VAL_BLE_MESH_LPN_SCAN_LATENCY (10)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS
#define MYNEWT_VAL_BLE_MESH_MODEL_EXTENSIONS (0)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT
#define MYNEWT_VAL_BLE_MESH_MODEL_GROUP_COUNT (1)
#endif
@ -866,10 +966,30 @@
#define MYNEWT_VAL_BLE_MESH_MODEL_KEY_COUNT (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_MODEL_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_MODEL_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_MODEL_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_MODEL_LOG_MOD (16)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE
#define MYNEWT_VAL_BLE_MESH_MSG_CACHE_SIZE (10)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_NET_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_NET_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_NET_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_NET_LOG_MOD (17)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_NODE_COUNT
#define MYNEWT_VAL_BLE_MESH_NODE_COUNT CONFIG_BT_NIMBLE_MESH_NODE_COUNT
#endif
#ifndef MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT
#define MYNEWT_VAL_BLE_MESH_NODE_ID_TIMEOUT (60)
#endif
@ -915,6 +1035,22 @@
#endif
#endif
#ifndef MYNEWT_VAL_BLE_MESH_PROVISIONER
#ifdef CONFIG_BT_NIMBLE_MESH_PROVISIONER
#define MYNEWT_VAL_BLE_MESH_PROVISIONER (1)
#else
#define MYNEWT_VAL_BLE_MESH_PROVISIONER (0)
#endif
#endif
#ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_PROV_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_PROV_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_PROV_LOG_MOD (18)
#endif
/* Overridden by @apache-mynewt-nimble/nimble/host/mesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */
#ifndef MYNEWT_VAL_BLE_MESH_PROXY
#ifdef CONFIG_BT_NIMBLE_MESH_PROXY
@ -928,6 +1064,13 @@
#define MYNEWT_VAL_BLE_MESH_PROXY_FILTER_SIZE (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_PROXY_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_PROXY_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_PROXY_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_PROXY_LOG_MOD (19)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_RELAY
#ifdef CONFIG_BT_NIMBLE_MESH_RELAY
@ -949,6 +1092,10 @@
#define MYNEWT_VAL_BLE_MESH_RX_SEG_MSG_COUNT (2)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS
#define MYNEWT_VAL_BLE_MESH_SEG_RETRANSMIT_ATTEMPTS (4)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE
#define MYNEWT_VAL_BLE_MESH_SEQ_STORE_RATE (128)
#endif
@ -958,6 +1105,14 @@
#define MYNEWT_VAL_BLE_MESH_SETTINGS (0)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_SETTINGS_LOG_MOD (20)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_SHELL
#define MYNEWT_VAL_BLE_MESH_SHELL (0)
#endif
@ -974,10 +1129,26 @@
#define MYNEWT_VAL_BLE_MESH_SUBNET_COUNT (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE
#define MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE (500)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE_SHELL
#define MYNEWT_VAL_BLE_MESH_SYSINIT_STAGE_SHELL (1000)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_TESTING
#define MYNEWT_VAL_BLE_MESH_TESTING (0)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_TRANS_LOG_LVL
#define MYNEWT_VAL_BLE_MESH_TRANS_LOG_LVL (1)
#endif
#ifndef MYNEWT_VAL_BLE_MESH_TRANS_LOG_MOD
#define MYNEWT_VAL_BLE_MESH_TRANS_LOG_MOD (21)
#endif
/* Overridden by apps/blemesh (defined by @apache-mynewt-nimble/nimble/host/mesh) */
#ifndef MYNEWT_VAL_BLE_MESH_TX_SEG_MAX
#define MYNEWT_VAL_BLE_MESH_TX_SEG_MAX (6)
@ -987,6 +1158,103 @@
#define MYNEWT_VAL_BLE_MESH_TX_SEG_MSG_COUNT (4)
#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)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_ANS_SYSINIT_STAGE
#define MYNEWT_VAL_BLE_SVC_ANS_SYSINIT_STAGE (303)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT
#define MYNEWT_VAL_BLE_SVC_ANS_UNR_ALERT_CAT (0)
#endif
/*** @apache-mynewt-nimble/nimble/host/services/bas */
#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE
#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_NOTIFY_ENABLE (1)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM
#define MYNEWT_VAL_BLE_SVC_BAS_BATTERY_LEVEL_READ_PERM (0)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE
#define MYNEWT_VAL_BLE_SVC_BAS_SYSINIT_STAGE (303)
#endif
/*** @apache-mynewt-nimble/nimble/host/services/dis */
#ifndef MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM
#define MYNEWT_VAL_BLE_SVC_DIS_DEFAULT_READ_PERM (-1)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT
#define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_DEFAULT (NULL)
#endif
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
#ifndef MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM
#define MYNEWT_VAL_BLE_SVC_DIS_FIRMWARE_REVISION_READ_PERM (-1)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT
#define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_DEFAULT (NULL)
#endif
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
#ifndef MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM
#define MYNEWT_VAL_BLE_SVC_DIS_HARDWARE_REVISION_READ_PERM (-1)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT
#define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_DEFAULT (NULL)
#endif
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
#ifndef MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM
#define MYNEWT_VAL_BLE_SVC_DIS_MANUFACTURER_NAME_READ_PERM (-1)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT
#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_DEFAULT ("NimBLE")
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM
#define MYNEWT_VAL_BLE_SVC_DIS_MODEL_NUMBER_READ_PERM (0)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT
#define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_DEFAULT (NULL)
#endif
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM
#define MYNEWT_VAL_BLE_SVC_DIS_SERIAL_NUMBER_READ_PERM (-1)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT
#define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_DEFAULT (NULL)
#endif
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM
#define MYNEWT_VAL_BLE_SVC_DIS_SOFTWARE_REVISION_READ_PERM (-1)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSINIT_STAGE
#define MYNEWT_VAL_BLE_SVC_DIS_SYSINIT_STAGE (303)
#endif
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_DEFAULT (NULL)
#endif
/* Value copied from BLE_SVC_DIS_DEFAULT_READ_PERM */
#ifndef MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM
#define MYNEWT_VAL_BLE_SVC_DIS_SYSTEM_ID_READ_PERM (-1)
#endif
/*** @apache-mynewt-nimble/nimble/host/services/gap */
#ifndef MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE
#define MYNEWT_VAL_BLE_SVC_GAP_APPEARANCE CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE
@ -1102,4 +1370,8 @@
#define MYNEWT_VAL_BLE_HCI_UART_STOP_BITS (1)
#endif
#ifndef MYNEWT_VAL_NEWT_FEATURE_LOGCFG
#define MYNEWT_VAL_NEWT_FEATURE_LOGCFG (1)
#endif
#endif

View File

@ -128,6 +128,7 @@ struct hci_conn_update;
#define BLE_GAP_EVENT_PERIODIC_REPORT 21
#define BLE_GAP_EVENT_PERIODIC_SYNC_LOST 22
#define BLE_GAP_EVENT_SCAN_REQ_RCVD 23
#define BLE_GAP_EVENT_PERIODIC_TRANSFER 24
/*** Reason codes for the subscribe GAP event. */
@ -390,7 +391,7 @@ struct ble_gap_ext_disc_desc {
uint8_t length_data;
/** Advertising data */
uint8_t *data;
const uint8_t *data;
/** Directed advertising address. Valid if BLE_HCI_ADV_DIRECT_MASK props is
* set (BLE_ADDR_ANY otherwise).
@ -420,7 +421,7 @@ struct ble_gap_disc_desc {
int8_t rssi;
/** Advertising data */
uint8_t *data;
const uint8_t *data;
/** Directed advertising address. Valid for BLE_HCI_ADV_RPT_EVTYPE_DIR_IND
* event type (BLE_ADDR_ANY otherwise).
@ -890,7 +891,7 @@ struct ble_gap_event {
uint8_t data_length;
/** Advertising data */
uint8_t *data;
const uint8_t *data;
} periodic_report;
/**
@ -924,6 +925,47 @@ struct ble_gap_event {
/** Address of scanner */
ble_addr_t scan_addr;
} scan_req_rcvd;
#endif
#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
/**
* Represents a periodic advertising sync transfer received. Valid for
* the following event types:
* o BLE_GAP_EVENT_PERIODIC_TRANSFER
*/
struct {
/** BLE_ERR_SUCCESS on success or error code on failure. Sync handle
* is valid only for success.
*/
uint8_t status;
/** Periodic sync handle */
uint16_t sync_handle;
/** Connection handle */
uint16_t conn_handle;
/** Service Data */
uint16_t service_data;
/** Advertising Set ID */
uint8_t sid;
/** Advertiser address */
ble_addr_t adv_addr;
/** Advertising PHY, can be one of following constants:
* - BLE_HCI_LE_PHY_1M
* - LE_HCI_LE_PHY_2M
* - BLE_HCI_LE_PHY_CODED
*/
uint8_t adv_phy;
/** Periodic advertising interval */
uint16_t per_adv_itvl;
/** Advertiser clock accuracy */
uint8_t adv_clk_accuracy;
} periodic_transfer;
#endif
};
};
@ -1097,6 +1139,23 @@ int ble_gap_adv_set_fields(const struct ble_hs_adv_fields *rsp_fields);
*/
int ble_gap_adv_rsp_set_fields(const struct ble_hs_adv_fields *rsp_fields);
/**
* Configure LE Data Length in controller (OGF = 0x08, OCF = 0x0022).
*
* @param conn_handle Connection handle.
* @param tx_octets The preferred value of payload octets that the Controller
* should use for a new connection (Range
* 0x001B-0x00FB).
* @param tx_time The preferred maximum number of microseconds that the local Controller
* should use to transmit a single link layer packet
* (Range 0x0148-0x4290).
*
* @return 0 on success,
* other error code on failure.
*/
int ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets,
uint16_t tx_time);
#if MYNEWT_VAL(BLE_EXT_ADV)
/** @brief Extended advertising parameters */
struct ble_gap_ext_adv_params {
@ -1203,8 +1262,8 @@ int ble_gap_ext_adv_set_addr(uint8_t instance, const ble_addr_t *addr);
* @param instance Instance ID
* @param duration The duration of the advertisement procedure. On
* expiration, the procedure ends and
* a BLE_HS_FOREVER event is reported.
* Units are milliseconds. Specify 0 for no
* a BLE_GAP_EVENT_ADV_COMPLETE event is reported.
* Units are 10 milliseconds. Specify 0 for no
* expiration.
* @params max_events Number of advertising events that should be sent
* before advertising ends and
@ -1297,6 +1356,9 @@ struct ble_gap_periodic_sync_params {
/** Synchronization timeout for the periodic advertising train in 10ms units
*/
uint16_t sync_timeout;
/** If reports should be initially disabled when sync is created */
unsigned int reports_disabled:1;
};
/**
@ -1359,7 +1421,7 @@ int ble_gap_periodic_adv_set_data(uint8_t instance, struct os_mbuf *data);
*
* @return 0 on success; nonzero on failure.
*/
int ble_gap_periodic_adv_create_sync(const ble_addr_t *addr, uint8_t adv_sid,
int ble_gap_periodic_adv_sync_create(const ble_addr_t *addr, uint8_t adv_sid,
const struct ble_gap_periodic_sync_params *params,
ble_gap_event_fn *cb, void *cb_arg);
@ -1368,7 +1430,7 @@ int ble_gap_periodic_adv_create_sync(const ble_addr_t *addr, uint8_t adv_sid,
*
* @return 0 on success; nonzero on failure.
*/
int ble_gap_periodic_adv_create_sync_cancel(void);
int ble_gap_periodic_adv_sync_create_cancel(void);
/**
* Terminate synchronization procedure.
@ -1377,7 +1439,74 @@ int ble_gap_periodic_adv_create_sync_cancel(void);
*
* @return 0 on success; nonzero on failure.
*/
int ble_gap_periodic_adv_terminate_sync(uint16_t sync_handle);
int ble_gap_periodic_adv_sync_terminate(uint16_t sync_handle);
#if MYNEWT_VAL(BLE_PERIODIC_ADV_SYNC_TRANSFER)
/**
* Disable or enable periodic reports for specified sync.
*
* @param sync_handle Handle identifying synchronization.
* @param enable If reports should be enabled.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gap_periodic_adv_sync_reporting(uint16_t sync_handle, bool enable);
/**
* Initialize sync transfer procedure for specified handles.
*
* This allows to transfer periodic sync to which host is synchronized.
*
* @param sync_handle Handle identifying synchronization.
* @param conn_handle Handle identifying connection.
* @param service_data Sync transfer service data
*
* @return 0 on success; nonzero on failure.
*/
int ble_gap_periodic_adv_sync_transfer(uint16_t sync_handle,
uint16_t conn_handle,
uint16_t service_data);
/**
* Initialize set info transfer procedure for specified handles.
*
* This allows to transfer periodic sync which is being advertised by host.
*
* @param instance Advertising instance with periodic adv enabled.
* @param conn_handle Handle identifying connection.
* @param service_data Sync transfer service data
*
* @return 0 on success; nonzero on failure.
*/
int ble_gap_periodic_adv_sync_set_info(uint8_t instance,
uint16_t conn_handle,
uint16_t service_data);
/**
* Enables or disables sync transfer reception on specified connection.
* When sync transfer arrives, BLE_GAP_EVENT_PERIODIC_TRANSFER is sent to the user.
* After that, sync transfer reception on that connection is terminated and user needs
* to call this API again when expect to receive next sync transfers.
*
* Note: If ACL connection gets disconnected before sync transfer arrived, user will
* not receive BLE_GAP_EVENT_PERIODIC_TRANSFER. Instead, sync transfer reception
* is terminated by the host automatically.
*
* @param conn_handle Handle identifying connection.
* @param params Parameters for enabled sync transfer reception.
* Specify NULL to disable reception.
* @param cb The callback to associate with this synchronization
* procedure. BLE_GAP_EVENT_PERIODIC_REPORT events
* are reported only by this callback.
* @param cb_arg The optional argument to pass to the callback
* function.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gap_periodic_adv_sync_receive(uint16_t conn_handle,
const struct ble_gap_periodic_sync_params *params,
ble_gap_event_fn *cb, void *cb_arg);
#endif
/**
* Add peer device to periodic synchronization list.
@ -1435,7 +1564,8 @@ int ble_gap_read_periodic_adv_list_size(uint8_t *per_adv_list_size);
* On expiration, the procedure ends and a
* BLE_GAP_EVENT_DISC_COMPLETE event is
* reported. Units are milliseconds. Specify
* BLE_HS_FOREVER for no expiration.
* BLE_HS_FOREVER for no expiration. Specify
* 0 to use stack defaults.
* @param disc_params Additional arguments specifying the particulars
* of the discovery procedure.
* @param cb The callback to associate with this discovery
@ -1661,6 +1791,15 @@ int ble_gap_terminate(uint16_t conn_handle, uint8_t hci_reason);
*/
int ble_gap_wl_set(const ble_addr_t *addrs, uint8_t white_list_count);
/**
* Removes the address from controller's white list.
*
* @param addrs The entry to be removed from the white list.
*
* @return 0 on success; nonzero on failure.
*/
int ble_gap_wl_tx_rmv(const ble_addr_t *addrs);
/**
* Initiates a connection parameter update procedure.
*

View File

@ -35,7 +35,7 @@ extern "C" {
struct ble_hs_adv_field {
uint8_t length;
uint8_t type;
uint8_t value[];
uint8_t value[0];
};
typedef int (* ble_hs_adv_parse_func_t) (const struct ble_hs_adv_field *,
@ -46,22 +46,22 @@ struct ble_hs_adv_fields {
uint8_t flags;
/*** 0x02,0x03 - 16-bit service class UUIDs. */
ble_uuid16_t *uuids16;
const ble_uuid16_t *uuids16;
uint8_t num_uuids16;
unsigned uuids16_is_complete:1;
/*** 0x04,0x05 - 32-bit service class UUIDs. */
ble_uuid32_t *uuids32;
const ble_uuid32_t *uuids32;
uint8_t num_uuids32;
unsigned uuids32_is_complete:1;
/*** 0x06,0x07 - 128-bit service class UUIDs. */
ble_uuid128_t *uuids128;
const ble_uuid128_t *uuids128;
uint8_t num_uuids128;
unsigned uuids128_is_complete:1;
/*** 0x08,0x09 - Local name. */
uint8_t *name;
const uint8_t *name;
uint8_t name_len;
unsigned name_is_complete:1;
@ -70,14 +70,14 @@ struct ble_hs_adv_fields {
unsigned tx_pwr_lvl_is_present:1;
/*** 0x0d - Slave connection interval range. */
uint8_t *slave_itvl_range;
const uint8_t *slave_itvl_range;
/*** 0x16 - Service data - 16-bit UUID. */
uint8_t *svc_data_uuid16;
const uint8_t *svc_data_uuid16;
uint8_t svc_data_uuid16_len;
/*** 0x17 - Public target address. */
uint8_t *public_tgt_addr;
const uint8_t *public_tgt_addr;
uint8_t num_public_tgt_addrs;
/*** 0x19 - Appearance. */
@ -89,19 +89,19 @@ struct ble_hs_adv_fields {
unsigned adv_itvl_is_present:1;
/*** 0x20 - Service data - 32-bit UUID. */
uint8_t *svc_data_uuid32;
const uint8_t *svc_data_uuid32;
uint8_t svc_data_uuid32_len;
/*** 0x21 - Service data - 128-bit UUID. */
uint8_t *svc_data_uuid128;
const uint8_t *svc_data_uuid128;
uint8_t svc_data_uuid128_len;
/*** 0x24 - URI. */
uint8_t *uri;
const uint8_t *uri;
uint8_t uri_len;
/*** 0xff - Manufacturer specific data. */
uint8_t *mfg_data;
const uint8_t *mfg_data;
uint8_t mfg_data_len;
};
@ -164,8 +164,8 @@ int ble_hs_adv_set_fields_mbuf(const struct ble_hs_adv_fields *adv_fields,
int ble_hs_adv_set_fields(const struct ble_hs_adv_fields *adv_fields,
uint8_t *dst, uint8_t *dst_len, uint8_t max_len);
int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields, uint8_t *src,
uint8_t src_len);
int ble_hs_adv_parse_fields(struct ble_hs_adv_fields *adv_fields,
const uint8_t *src, uint8_t src_len);
int ble_hs_adv_parse(const uint8_t *data, uint8_t length,
ble_hs_adv_parse_func_t func, void *user_data);

View File

@ -22,6 +22,11 @@
#include "modlog/modlog.h"
/* Only include the logcfg header if this version of newt can generate it. */
#if MYNEWT_VAL(NEWT_FEATURE_LOGCFG)
#include "logcfg/logcfg.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
@ -29,13 +34,13 @@ extern "C" {
struct os_mbuf;
#define BLE_HS_LOG(lvl, ...) \
MODLOG_ ## lvl(LOG_MODULE_NIMBLE_HOST, __VA_ARGS__)
BLE_HS_LOG_ ## lvl(__VA_ARGS__)
#define BLE_HS_LOG_ADDR(lvl, addr) \
MODLOG_ ## lvl(LOG_MODULE_NIMBLE_HOST, \
"%02x:%02x:%02x:%02x:%02x:%02x", \
(addr)[5], (addr)[4], (addr)[3], \
(addr)[2], (addr)[1], (addr)[0])
BLE_HS_LOG_ ## lvl("%02x:%02x:%02x:%02x:%02x:%02x", \
(addr)[5], (addr)[4], (addr)[3], \
(addr)[2], (addr)[1], (addr)[0])
void ble_hs_log_mbuf(const struct os_mbuf *om);
void ble_hs_log_flat_buf(const void *data, int len);

View File

@ -51,10 +51,14 @@ struct ble_hs_conn;
#define BLE_L2CAP_SIG_OP_MOVE_CHAN_CONF_RSP 0x11
#define BLE_L2CAP_SIG_OP_UPDATE_REQ 0x12
#define BLE_L2CAP_SIG_OP_UPDATE_RSP 0x13
#define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ 0x14
#define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_RSP 0x15
#define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_REQ 0x14
#define BLE_L2CAP_SIG_OP_LE_CREDIT_CONNECT_RSP 0x15
#define BLE_L2CAP_SIG_OP_FLOW_CTRL_CREDIT 0x16
#define BLE_L2CAP_SIG_OP_MAX 0x17
#define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_REQ 0x17
#define BLE_L2CAP_SIG_OP_CREDIT_CONNECT_RSP 0x18
#define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_REQ 0x19
#define BLE_L2CAP_SIG_OP_CREDIT_RECONFIG_RSP 0x1A
#define BLE_L2CAP_SIG_OP_MAX 0x1B
#define BLE_L2CAP_SIG_ERR_CMD_NOT_UNDERSTOOD 0x0000
#define BLE_L2CAP_SIG_ERR_MTU_EXCEEDED 0x0001
@ -70,12 +74,21 @@ struct ble_hs_conn;
#define BLE_L2CAP_COC_ERR_INVALID_SOURCE_CID 0x0009
#define BLE_L2CAP_COC_ERR_SOURCE_CID_ALREADY_USED 0x000A
#define BLE_L2CAP_COC_ERR_UNACCEPTABLE_PARAMETERS 0x000B
#define BLE_L2CAP_COC_ERR_INVALID_PARAMETERS 0x000C
#define BLE_L2CAP_ERR_RECONFIG_SUCCEED 0x0000
#define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MTU_NOT_ALLOWED 0x0001
#define BLE_L2CAP_ERR_RECONFIG_REDUCTION_MPS_NOT_ALLOWED 0x0002
#define BLE_L2CAP_ERR_RECONFIG_INVALID_DCID 0x0003
#define BLE_L2CAP_ERR_RECONFIG_UNACCAPTED_PARAM 0x0004
#define BLE_L2CAP_EVENT_COC_CONNECTED 0
#define BLE_L2CAP_EVENT_COC_DISCONNECTED 1
#define BLE_L2CAP_EVENT_COC_ACCEPT 2
#define BLE_L2CAP_EVENT_COC_DATA_RECEIVED 3
#define BLE_L2CAP_EVENT_COC_TX_UNSTALLED 4
#define BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED 5
#define BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED 6
typedef void ble_l2cap_sig_update_fn(uint16_t conn_handle, int status,
void *arg);
@ -196,11 +209,44 @@ struct ble_l2cap_event {
*/
int status;
} tx_unstalled;
/**
* Represents reconfiguration done. Valid for the following event
* types:
* o BLE_L2CAP_EVENT_COC_RECONFIG_COMPLETED
* o BLE_L2CAP_EVENT_COC_PEER_RECONFIGURED
*/
struct {
/**
* The status of the reconfiguration attempt;
* o 0: the reconfiguration was successfully done.
* o BLE host error code: the reconfiguration attempt failed for
* the specified reason.
*/
int status;
/** Connection handle of the relevant connection */
uint16_t conn_handle;
/** The L2CAP channel of the relevant L2CAP connection. */
struct ble_l2cap_chan *chan;
} reconfigured;
};
};
struct ble_l2cap_chan_info {
uint16_t scid;
uint16_t dcid;
uint16_t our_l2cap_mtu;
uint16_t peer_l2cap_mtu;
uint16_t psm;
uint16_t our_coc_mtu;
uint16_t peer_coc_mtu;
};
typedef int ble_l2cap_event_fn(struct ble_l2cap_event *event, void *arg);
uint16_t ble_l2cap_get_conn_handle(struct ble_l2cap_chan *chan);
int ble_l2cap_create_server(uint16_t psm, uint16_t mtu,
ble_l2cap_event_fn *cb, void *cb_arg);
@ -211,10 +257,7 @@ int ble_l2cap_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
int ble_l2cap_disconnect(struct ble_l2cap_chan *chan);
int ble_l2cap_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx);
int ble_l2cap_recv_ready(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_rx);
int ble_l2cap_get_scid(struct ble_l2cap_chan *chan);
int ble_l2cap_get_dcid(struct ble_l2cap_chan *chan);
int ble_l2cap_get_our_mtu(struct ble_l2cap_chan *chan);
int ble_l2cap_get_peer_mtu(struct ble_l2cap_chan *chan);
int ble_l2cap_get_chan_info(struct ble_l2cap_chan *chan, struct ble_l2cap_chan_info *chan_info);
#ifdef __cplusplus
}

View File

@ -84,7 +84,16 @@ extern "C" {
#define BLE_SM_IOACT_INPUT 2
#define BLE_SM_IOACT_DISP 3
#define BLE_SM_IOACT_NUMCMP 4
#define BLE_SM_IOACT_MAX_PLUS_ONE 5
#define BLE_SM_IOACT_OOB_SC 5
#define BLE_SM_IOACT_MAX_PLUS_ONE 6
struct ble_sm_sc_oob_data {
/** Random Number. */
uint8_t r[16];
/** Confirm Value. */
uint8_t c[16];
};
struct ble_sm_io {
uint8_t action;
@ -92,9 +101,15 @@ struct ble_sm_io {
uint32_t passkey;
uint8_t oob[16];
uint8_t numcmp_accept;
struct {
struct ble_sm_sc_oob_data *local;
struct ble_sm_sc_oob_data *remote;
} oob_sc_data;
};
};
int ble_sm_sc_oob_generate_data(struct ble_sm_sc_oob_data *oob_data);
#if NIMBLE_BLE_SM
int ble_sm_inject_io(uint16_t conn_handle, struct ble_sm_io *pkey);
#else

View File

@ -0,0 +1,64 @@
/*
* 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_IGNORE_
#define H_IGNORE_
#ifdef __cplusplus
extern "C" {
#endif
/**
* These macros prevent the "set but not used" warnings for log writes below
* the log level.
*/
#define IGN_1(X) ((void)(X))
#define IGN_2(X, ...) ((void)(X));IGN_1(__VA_ARGS__)
#define IGN_3(X, ...) ((void)(X));IGN_2(__VA_ARGS__)
#define IGN_4(X, ...) ((void)(X));IGN_3(__VA_ARGS__)
#define IGN_5(X, ...) ((void)(X));IGN_4(__VA_ARGS__)
#define IGN_6(X, ...) ((void)(X));IGN_5(__VA_ARGS__)
#define IGN_7(X, ...) ((void)(X));IGN_6(__VA_ARGS__)
#define IGN_8(X, ...) ((void)(X));IGN_7(__VA_ARGS__)
#define IGN_9(X, ...) ((void)(X));IGN_8(__VA_ARGS__)
#define IGN_10(X, ...) ((void)(X));IGN_9(__VA_ARGS__)
#define IGN_11(X, ...) ((void)(X));IGN_10(__VA_ARGS__)
#define IGN_12(X, ...) ((void)(X));IGN_11(__VA_ARGS__)
#define IGN_13(X, ...) ((void)(X));IGN_12(__VA_ARGS__)
#define IGN_14(X, ...) ((void)(X));IGN_13(__VA_ARGS__)
#define IGN_15(X, ...) ((void)(X));IGN_14(__VA_ARGS__)
#define IGN_16(X, ...) ((void)(X));IGN_15(__VA_ARGS__)
#define IGN_17(X, ...) ((void)(X));IGN_16(__VA_ARGS__)
#define IGN_18(X, ...) ((void)(X));IGN_17(__VA_ARGS__)
#define IGN_19(X, ...) ((void)(X));IGN_18(__VA_ARGS__)
#define IGN_20(X, ...) ((void)(X));IGN_19(__VA_ARGS__)
#define GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, \
_13, _14, _15, _16, _17, _18, _19, _20, NAME, ...) NAME
#define IGNORE(...) \
GET_MACRO(__VA_ARGS__, IGN_20, IGN_19, IGN_18, IGN_17, IGN_16, IGN_15, \
IGN_14, IGN_13, IGN_12, IGN_11, IGN_10, IGN_9, IGN_8, IGN_7, \
IGN_6, IGN_5, IGN_4, IGN_3, IGN_2, IGN_1)(__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif

View File

@ -17,18 +17,26 @@
* under the License.
*/
#ifndef H_BLE_HS_DBG_PRIV_
#define H_BLE_HS_DBG_PRIV_
#ifndef H_LOG_COMMON_
#define H_LOG_COMMON_
#include "log_common/ignore.h"
#ifdef __cplusplus
extern "C" {
#endif
void ble_hs_dbg_event_disp(uint8_t *evbuf);
void ble_hs_dbg_set_sync_state(uint8_t sync_state);
#define LOG_LEVEL_DEBUG (0)
#define LOG_LEVEL_INFO (1)
#define LOG_LEVEL_WARN (2)
#define LOG_LEVEL_ERROR (3)
#define LOG_LEVEL_CRITICAL (4)
#define LOG_LEVEL_NONE (5)
/* Up to 7 custom log levels. */
#define LOG_LEVEL_MAX (15)
#ifdef __cplusplus
}
#endif
#endif /* H_HOST_DBG_ */
#endif

View File

@ -0,0 +1,147 @@
/**
* This file was generated by Apache newt version: 1.8.0-dev
*/
#ifndef H_MYNEWT_LOGCFG_
#define H_MYNEWT_LOGCFG_
#include "modlog/modlog.h"
#include "log_common/log_common.h"
#if (MYNEWT_VAL(BLE_HS_LOG_LVL) == LOG_LEVEL_DEBUG)
#define BLE_HS_LOG_DEBUG(...) MODLOG_DEBUG(4, __VA_ARGS__)
#else
#define BLE_HS_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#endif
#if (MYNEWT_VAL(BLE_HS_LOG_LVL) <= LOG_LEVEL_INFO)
#define BLE_HS_LOG_INFO(...) MODLOG_INFO(4, __VA_ARGS__)
#else
#define BLE_HS_LOG_INFO(...) IGNORE(__VA_ARGS__)
#endif
#if (MYNEWT_VAL(BLE_HS_LOG_LVL) <= LOG_LEVEL_WARN)
#define BLE_HS_LOG_WARN(...) MODLOG_WARN(4, __VA_ARGS__)
#else
#define BLE_HS_LOG_WARN(...) IGNORE(__VA_ARGS__)
#endif
#if (MYNEWT_VAL(BLE_HS_LOG_LVL) <= LOG_LEVEL_ERROR)
#define BLE_HS_LOG_ERROR(...) MODLOG_ERROR(4, __VA_ARGS__)
#else
#define BLE_HS_LOG_ERROR(...) IGNORE(__VA_ARGS__)
#endif
#if (MYNEWT_VAL(BLE_HS_LOG_LVL) <= LOG_LEVEL_CRITICAL)
#define BLE_HS_LOG_CRITICAL(...) MODLOG_CRITICAL(4, __VA_ARGS__)
#else
#define BLE_HS_LOG_CRITICAL(...) IGNORE(__VA_ARGS__)
#endif
#define BLE_HS_LOG_DISABLED(...) MODLOG_DISABLED(4, __VA_ARGS__)
#define BLE_MESH_ACCESS_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_ACCESS_LOG_INFO(...) MODLOG_INFO(10, __VA_ARGS__)
#define BLE_MESH_ACCESS_LOG_WARN(...) MODLOG_WARN(10, __VA_ARGS__)
#define BLE_MESH_ACCESS_LOG_ERROR(...) MODLOG_ERROR(10, __VA_ARGS__)
#define BLE_MESH_ACCESS_LOG_CRITICAL(...) MODLOG_CRITICAL(10, __VA_ARGS__)
#define BLE_MESH_ACCESS_LOG_DISABLED(...) MODLOG_DISABLED(10, __VA_ARGS__)
#define BLE_MESH_ADV_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_ADV_LOG_INFO(...) MODLOG_INFO(11, __VA_ARGS__)
#define BLE_MESH_ADV_LOG_WARN(...) MODLOG_WARN(11, __VA_ARGS__)
#define BLE_MESH_ADV_LOG_ERROR(...) MODLOG_ERROR(11, __VA_ARGS__)
#define BLE_MESH_ADV_LOG_CRITICAL(...) MODLOG_CRITICAL(11, __VA_ARGS__)
#define BLE_MESH_ADV_LOG_DISABLED(...) MODLOG_DISABLED(11, __VA_ARGS__)
#define BLE_MESH_BEACON_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_BEACON_LOG_INFO(...) MODLOG_INFO(12, __VA_ARGS__)
#define BLE_MESH_BEACON_LOG_WARN(...) MODLOG_WARN(12, __VA_ARGS__)
#define BLE_MESH_BEACON_LOG_ERROR(...) MODLOG_ERROR(12, __VA_ARGS__)
#define BLE_MESH_BEACON_LOG_CRITICAL(...) MODLOG_CRITICAL(12, __VA_ARGS__)
#define BLE_MESH_BEACON_LOG_DISABLED(...) MODLOG_DISABLED(12, __VA_ARGS__)
#define BLE_MESH_CRYPTO_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_CRYPTO_LOG_INFO(...) MODLOG_INFO(13, __VA_ARGS__)
#define BLE_MESH_CRYPTO_LOG_WARN(...) MODLOG_WARN(13, __VA_ARGS__)
#define BLE_MESH_CRYPTO_LOG_ERROR(...) MODLOG_ERROR(13, __VA_ARGS__)
#define BLE_MESH_CRYPTO_LOG_CRITICAL(...) MODLOG_CRITICAL(13, __VA_ARGS__)
#define BLE_MESH_CRYPTO_LOG_DISABLED(...) MODLOG_DISABLED(13, __VA_ARGS__)
#define BLE_MESH_FRIEND_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_FRIEND_LOG_INFO(...) MODLOG_INFO(14, __VA_ARGS__)
#define BLE_MESH_FRIEND_LOG_WARN(...) MODLOG_WARN(14, __VA_ARGS__)
#define BLE_MESH_FRIEND_LOG_ERROR(...) MODLOG_ERROR(14, __VA_ARGS__)
#define BLE_MESH_FRIEND_LOG_CRITICAL(...) MODLOG_CRITICAL(14, __VA_ARGS__)
#define BLE_MESH_FRIEND_LOG_DISABLED(...) MODLOG_DISABLED(14, __VA_ARGS__)
#define BLE_MESH_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_LOG_INFO(...) MODLOG_INFO(9, __VA_ARGS__)
#define BLE_MESH_LOG_WARN(...) MODLOG_WARN(9, __VA_ARGS__)
#define BLE_MESH_LOG_ERROR(...) MODLOG_ERROR(9, __VA_ARGS__)
#define BLE_MESH_LOG_CRITICAL(...) MODLOG_CRITICAL(9, __VA_ARGS__)
#define BLE_MESH_LOG_DISABLED(...) MODLOG_DISABLED(9, __VA_ARGS__)
#define BLE_MESH_LOW_POWER_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_LOW_POWER_LOG_INFO(...) MODLOG_INFO(15, __VA_ARGS__)
#define BLE_MESH_LOW_POWER_LOG_WARN(...) MODLOG_WARN(15, __VA_ARGS__)
#define BLE_MESH_LOW_POWER_LOG_ERROR(...) MODLOG_ERROR(15, __VA_ARGS__)
#define BLE_MESH_LOW_POWER_LOG_CRITICAL(...) MODLOG_CRITICAL(15, __VA_ARGS__)
#define BLE_MESH_LOW_POWER_LOG_DISABLED(...) MODLOG_DISABLED(15, __VA_ARGS__)
#define BLE_MESH_MODEL_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_MODEL_LOG_INFO(...) MODLOG_INFO(16, __VA_ARGS__)
#define BLE_MESH_MODEL_LOG_WARN(...) MODLOG_WARN(16, __VA_ARGS__)
#define BLE_MESH_MODEL_LOG_ERROR(...) MODLOG_ERROR(16, __VA_ARGS__)
#define BLE_MESH_MODEL_LOG_CRITICAL(...) MODLOG_CRITICAL(16, __VA_ARGS__)
#define BLE_MESH_MODEL_LOG_DISABLED(...) MODLOG_DISABLED(16, __VA_ARGS__)
#define BLE_MESH_NET_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_NET_LOG_INFO(...) MODLOG_INFO(17, __VA_ARGS__)
#define BLE_MESH_NET_LOG_WARN(...) MODLOG_WARN(17, __VA_ARGS__)
#define BLE_MESH_NET_LOG_ERROR(...) MODLOG_ERROR(17, __VA_ARGS__)
#define BLE_MESH_NET_LOG_CRITICAL(...) MODLOG_CRITICAL(17, __VA_ARGS__)
#define BLE_MESH_NET_LOG_DISABLED(...) MODLOG_DISABLED(17, __VA_ARGS__)
#define BLE_MESH_PROV_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_PROV_LOG_INFO(...) MODLOG_INFO(18, __VA_ARGS__)
#define BLE_MESH_PROV_LOG_WARN(...) MODLOG_WARN(18, __VA_ARGS__)
#define BLE_MESH_PROV_LOG_ERROR(...) MODLOG_ERROR(18, __VA_ARGS__)
#define BLE_MESH_PROV_LOG_CRITICAL(...) MODLOG_CRITICAL(18, __VA_ARGS__)
#define BLE_MESH_PROV_LOG_DISABLED(...) MODLOG_DISABLED(18, __VA_ARGS__)
#define BLE_MESH_PROXY_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_PROXY_LOG_INFO(...) MODLOG_INFO(19, __VA_ARGS__)
#define BLE_MESH_PROXY_LOG_WARN(...) MODLOG_WARN(19, __VA_ARGS__)
#define BLE_MESH_PROXY_LOG_ERROR(...) MODLOG_ERROR(19, __VA_ARGS__)
#define BLE_MESH_PROXY_LOG_CRITICAL(...) MODLOG_CRITICAL(19, __VA_ARGS__)
#define BLE_MESH_PROXY_LOG_DISABLED(...) MODLOG_DISABLED(19, __VA_ARGS__)
#define BLE_MESH_SETTINGS_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_SETTINGS_LOG_INFO(...) MODLOG_INFO(20, __VA_ARGS__)
#define BLE_MESH_SETTINGS_LOG_WARN(...) MODLOG_WARN(20, __VA_ARGS__)
#define BLE_MESH_SETTINGS_LOG_ERROR(...) MODLOG_ERROR(20, __VA_ARGS__)
#define BLE_MESH_SETTINGS_LOG_CRITICAL(...) MODLOG_CRITICAL(20, __VA_ARGS__)
#define BLE_MESH_SETTINGS_LOG_DISABLED(...) MODLOG_DISABLED(20, __VA_ARGS__)
#define BLE_MESH_TRANS_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_MESH_TRANS_LOG_INFO(...) MODLOG_INFO(21, __VA_ARGS__)
#define BLE_MESH_TRANS_LOG_WARN(...) MODLOG_WARN(21, __VA_ARGS__)
#define BLE_MESH_TRANS_LOG_ERROR(...) MODLOG_ERROR(21, __VA_ARGS__)
#define BLE_MESH_TRANS_LOG_CRITICAL(...) MODLOG_CRITICAL(21, __VA_ARGS__)
#define BLE_MESH_TRANS_LOG_DISABLED(...) MODLOG_DISABLED(21, __VA_ARGS__)
#define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__)
#define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__)
#define DFLT_LOG_ERROR(...) MODLOG_ERROR(0, __VA_ARGS__)
#define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__)
#define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__)
#define MFG_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define MFG_LOG_INFO(...) IGNORE(__VA_ARGS__)
#define MFG_LOG_WARN(...) IGNORE(__VA_ARGS__)
#define MFG_LOG_ERROR(...) IGNORE(__VA_ARGS__)
#define MFG_LOG_CRITICAL(...) IGNORE(__VA_ARGS__)
#define MFG_LOG_DISABLED(...) MODLOG_DISABLED(128, __VA_ARGS__)
#endif

View File

@ -29,6 +29,12 @@ extern "C" {
#define BT_MESH_KEY_UNUSED 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_IS_DEV_KEY(key) (key == BT_MESH_KEY_DEV_LOCAL || \
key == BT_MESH_KEY_DEV_REMOTE)
/** Helper to define a mesh element within an array.
*
@ -137,11 +143,14 @@ struct bt_mesh_msg_ctx {
/** Destination address of a received message. Not used for sending. */
u16_t recv_dst;
/** RSSI of received packet. Not used for sending. */
s8_t recv_rssi;
/** Received TTL value. Not used for sending. */
u8_t recv_ttl:7;
u8_t recv_ttl;
/** Force sending reliably by using segment acknowledgement */
u8_t send_rel:1;
bool send_rel;
/** TTL, or BT_MESH_TTL_DEFAULT for default TTL. */
u8_t send_ttl;
@ -171,7 +180,66 @@ struct bt_mesh_model_op {
/** Helper to define an empty model array */
#define BT_MESH_MODEL_NONE ((struct bt_mesh_model []){})
#define BT_MESH_MODEL(_id, _op, _pub, _user_data) \
/** Length of a short Mesh MIC. */
#define BT_MESH_MIC_SHORT 4
/** Length of a long Mesh MIC. */
#define BT_MESH_MIC_LONG 8
/** @def BT_MESH_MODEL_OP_LEN
*
* @brief Helper to determine the length of an opcode.
*
* @param _op Opcode.
*/
#define BT_MESH_MODEL_OP_LEN(_op) ((_op) <= 0xff ? 1 : (_op) <= 0xffff ? 2 : 3)
/** @def BT_MESH_MODEL_BUF_LEN
*
* @brief Helper for model message buffer length.
*
* Returns the length of a Mesh model message buffer, including the opcode
* length and a short MIC.
*
* @param _op Opcode of the message.
* @param _payload_len Length of the model payload.
*/
#define BT_MESH_MODEL_BUF_LEN(_op, _payload_len) \
(BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_SHORT)
/** @def BT_MESH_MODEL_BUF_LEN_LONG_MIC
*
* @brief Helper for model message buffer length.
*
* Returns the length of a Mesh model message buffer, including the opcode
* length and a long MIC.
*
* @param _op Opcode of the message.
* @param _payload_len Length of the model payload.
*/
#define BT_MESH_MODEL_BUF_LEN_LONG_MIC(_op, _payload_len) \
(BT_MESH_MODEL_OP_LEN(_op) + (_payload_len) + BT_MESH_MIC_LONG)
/** @def BT_MESH_MODEL_BUF_DEFINE
*
* @brief Define a Mesh model message buffer using @ref NET_BUF_SIMPLE.
*
* @param _op Opcode of the message.
* @param _payload_len Length of the model message payload.
*/
#define BT_MESH_MODEL_BUF(_op, _payload_len) \
NET_BUF_SIMPLE(BT_MESH_MODEL_BUF_LEN(_op, (_payload_len)))
/** @def BT_MESH_MODEL_CB
*
* @brief Composition data SIG model entry with callback functions.
*
* @param _id Model ID.
* @param _op Array of model opcode handlers.
* @param _pub Model publish parameters.
* @param _user_data User data for the model.
* @param _cb Callback structure, or NULL to keep no callbacks.
*/
#define BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, _cb) \
{ \
.id = (_id), \
.op = _op, \
@ -181,9 +249,21 @@ struct bt_mesh_model_op {
.groups = { [0 ... (CONFIG_BT_MESH_MODEL_GROUP_COUNT - 1)] = \
BT_MESH_ADDR_UNASSIGNED }, \
.user_data = _user_data, \
.cb = _cb, \
}
#define BT_MESH_MODEL_VND(_company, _id, _op, _pub, _user_data) \
/** @def BT_MESH_MODEL_VND_CB
*
* @brief Composition data vendor model entry with callback functions.
*
* @param _company Company ID.
* @param _id Model ID.
* @param _op Array of model opcode handlers.
* @param _pub Model publish parameters.
* @param _user_data User data for the model.
* @param _cb Callback structure, or NULL to keep no callbacks.
*/
#define BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, _cb) \
{ \
.vnd.company = (_company), \
.vnd.id = (_id), \
@ -194,8 +274,35 @@ struct bt_mesh_model_op {
.groups = { [0 ... (CONFIG_BT_MESH_MODEL_GROUP_COUNT - 1)] = \
BT_MESH_ADDR_UNASSIGNED }, \
.user_data = _user_data, \
.cb = _cb, \
}
/** @def BT_MESH_MODEL
*
* @brief Composition data SIG model entry.
*
* @param _id Model ID.
* @param _op Array of model opcode handlers.
* @param _pub Model publish parameters.
* @param _user_data User data for the model.
*/
#define BT_MESH_MODEL(_id, _op, _pub, _user_data) \
BT_MESH_MODEL_CB(_id, _op, _pub, _user_data, NULL)
/** @def BT_MESH_MODEL_VND
*
* @brief Composition data vendor model entry.
*
* @param _company Company ID.
* @param _id Model ID.
* @param _op Array of model opcode handlers.
* @param _pub Model publish parameters.
* @param _user_data User data for the model.
*/
#define BT_MESH_MODEL_VND(_company, _id, _op, _pub, _user_data) \
BT_MESH_MODEL_VND_CB(_company, _id, _op, _pub, _user_data, NULL)
/** @def BT_MESH_TRANSMIT
*
* @brief Encode transmission count & interval steps.
@ -276,6 +383,7 @@ struct bt_mesh_model_pub {
u8_t period; /**< Publish Period. */
u8_t period_div:4, /**< Divisor for the Period. */
cred:1, /**< Friendship Credentials Flag. */
fast_period:1,/**< Use FastPeriodDivisor */
count:3; /**< Retransmissions left. */
u32_t period_start; /**< Start of the current period. */
@ -317,6 +425,52 @@ struct bt_mesh_model_pub {
struct k_delayed_work timer;
};
/** Model callback functions. */
struct bt_mesh_model_cb {
/** @brief Set value handler of user data tied to the model.
*
* @sa settings_handler::h_set
*
* @param model Model to set the persistent data of.
* @param val Data from the backend.
*
* @return 0 on success, error otherwise.
*/
int (*const settings_set)(struct bt_mesh_model *model, char *val);
/** @brief Callback called when all settings have been loaded.
*
* This handler gets called after the settings have been loaded in
* full.
*
* @sa settings_handler::h_commit
*
* @param model Model this callback belongs to.
*
* @return 0 on success, error otherwise.
*/
int (*const settings_commit)(struct bt_mesh_model *model);
/** @brief Model init callback.
*
* Called on every model instance during mesh initialization.
*
* @param model Model to be initialized.
*
* @return 0 on success, error otherwise.
*/
int (*const init)(struct bt_mesh_model *model);
/** @brief Model reset callback.
*
* Called when the mesh node is reset. All model data is deleted on
* reset, and the model should clear its state.
*
* @param model Model this callback belongs to.
*/
void (*const reset)(struct bt_mesh_model *model);
};
/** Abstraction that describes a Mesh Model instance */
struct bt_mesh_model {
union {
@ -330,7 +484,7 @@ struct bt_mesh_model {
/* 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; /* Information about what has changed */
u16_t flags; /* Model flags for internal bookkeeping */
/* Model Publication */
struct bt_mesh_model_pub * const pub;
@ -343,6 +497,15 @@ struct bt_mesh_model {
const struct bt_mesh_model_op * const op;
/* Model callback structure. */
const struct bt_mesh_model_cb * const cb;
#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS)
/* Pointer to the next model in a model extension tree. */
struct bt_mesh_model *next;
/* Pointer to the first model this model extends. */
struct bt_mesh_model *extends;
#endif
/* Model-specific user data */
void *user_data;
};
@ -402,6 +565,76 @@ int bt_mesh_model_publish(struct bt_mesh_model *model);
*/
struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod);
/** @brief Find a SIG model.
*
* @param elem Element to search for the model in.
* @param id Model ID of the model.
*
* @return A pointer to the Mesh model matching the given parameters, or NULL
* 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);
/** @brief Find a vendor model.
*
* @param elem Element to search for the model in.
* @param company Company ID of the model.
* @param id Model ID of the model.
*
* @return A pointer to the Mesh model matching the given parameters, or NULL
* 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);
/** @brief Get whether the model is in the primary element of the device.
*
* @param mod Mesh model.
*
* @return true if the model is on the primary element, false otherwise.
*/
static inline bool bt_mesh_model_in_primary(const struct bt_mesh_model *mod)
{
return (mod->elem_idx == 0);
}
/** @brief Immediately store the model's user data in persistent storage.
*
* @param mod Mesh model.
* @param vnd This is a vendor model.
* @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);
/** @brief Let a model extend another.
*
* Mesh models may be extended to reuse their functionality, forming a more
* complex model. A Mesh model may extend any number of models, in any element.
* The extensions may also be nested, ie a model that extends another may itself
* be extended. Extensions may not be cyclical, and a model can only be extended
* by one other model.
*
* A set of models that extend each other form a model extension tree.
*
* All models in an extension tree share one subscription list per element. The
* access layer will utilize the combined subscription list of all models in an
* extension tree and element, giving the models extended subscription list
* capacity.
*
* @param[in] mod Mesh model.
* @param[in] base_mod The model being extended.
*
* @retval 0 Successfully extended the base_mod model.
* @retval -EALREADY The base_mod model is already extended.
*/
int bt_mesh_model_extend(struct bt_mesh_model *mod,
struct bt_mesh_model *base_mod);
/** Node Composition */
struct bt_mesh_comp {
u16_t cid;

View File

@ -31,10 +31,11 @@ struct bt_mesh_cfg_cli {
};
extern const struct bt_mesh_model_op bt_mesh_cfg_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb;
#define BT_MESH_MODEL_CFG_CLI(cli_data) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_CFG_CLI, \
bt_mesh_cfg_cli_op, NULL, cli_data)
#define BT_MESH_MODEL_CFG_CLI(cli_data) \
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);

View File

@ -61,10 +61,11 @@ struct bt_mesh_cfg_srv {
};
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) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_CFG_SRV, \
bt_mesh_cfg_srv_op, NULL, srv_data)
#define BT_MESH_MODEL_CFG_SRV(srv_data) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_op, NULL, \
srv_data, &bt_mesh_cfg_srv_cb)
#ifdef __cplusplus
}

View File

@ -24,6 +24,8 @@
#include <errno.h>
#include "syscfg/syscfg.h"
#include "logcfg/logcfg.h"
#include "modlog/modlog.h"
#include "nimble/nimble_npl.h"
#include "os/os_mbuf.h"
@ -179,13 +181,19 @@ extern "C" {
#define BT_GAP_ADV_SLOW_INT_MIN 0x0640 /* 1 s */
#define BT_GAP_ADV_SLOW_INT_MAX 0x0780 /* 1.2 s */
#define BT_DBG(fmt, ...) \
if (BT_DBG_ENABLED) { \
BLE_HS_LOG(DEBUG, "%s: " fmt "\n", __func__, ## __VA_ARGS__); \
}
#define BT_INFO(fmt, ...) BLE_HS_LOG(INFO, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_WARN(fmt, ...) BLE_HS_LOG(WARN, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_ERR(fmt, ...) BLE_HS_LOG(ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#ifndef MESH_LOG_MODULE
#define MESH_LOG_MODULE BLE_MESH_LOG
#endif
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define BLE_MESH_LOG(lvl, ...) CAT(MESH_LOG_MODULE, CAT(_, lvl))(__VA_ARGS__)
#define BT_DBG(fmt, ...) BLE_MESH_LOG(DEBUG, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_INFO(fmt, ...) BLE_MESH_LOG(INFO, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_WARN(fmt, ...) BLE_MESH_LOG(WARN, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_ERR(fmt, ...) BLE_MESH_LOG(ERROR, "%s: " fmt "\n", __func__, ## __VA_ARGS__);
#define BT_GATT_ERR(_att_err) (-(_att_err))
typedef ble_addr_t bt_addr_le_t;
@ -217,6 +225,20 @@ static inline struct os_mbuf * NET_BUF_SIMPLE(uint16_t size)
#define K_NO_WAIT (0)
#define K_FOREVER (-1)
#if MYNEWT_VAL(BLE_EXT_ADV)
#define BT_MESH_ADV_INST (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES))
#if MYNEWT_VAL(BLE_MESH_PROXY)
/* Note that BLE_MULTI_ADV_INSTANCES contains number of additional instances.
* Instance 0 is always there
*/
#if MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) < 1
#error "Mesh needs at least BLE_MULTI_ADV_INSTANCES set to 1"
#endif
#define BT_MESH_ADV_GATT_INST (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) - 1)
#endif /* BLE_MESH_PROXY */
#endif /* BLE_EXT_ADV */
/* This is by purpose */
static inline void net_buf_simple_init(struct os_mbuf *buf,
size_t reserve_head)
@ -260,6 +282,11 @@ 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_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)
#define net_buf_skip(a, b) net_buf_simple_pull_mem(a, b)
#define BT_GATT_CCC_NOTIFY BLE_GATT_CHR_PROP_NOTIFY
@ -370,9 +397,11 @@ static inline unsigned int find_msb_set(u32_t op)
#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
/* Above flags are used with IS_ENABLED macro */
#define IS_ENABLED(config) MYNEWT_VAL(config)
@ -394,6 +423,8 @@ static inline unsigned int find_msb_set(u32_t op)
#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 printk console_printf
@ -459,7 +490,8 @@ void net_buf_slist_merge_slist(struct net_buf_slist_t *list,
#define settings_load conf_load
int settings_bytes_from_str(char *val_str, void *vp, int *len);
char *settings_str_from_bytes(void *vp, int vp_len, char *buf, int buf_len);
char *settings_str_from_bytes(const void *vp, int vp_len,
char *buf, int buf_len);
#define snprintk snprintf
#define BT_SETTINGS_SIZE(in_size) ((((((in_size) - 1) / 3) * 4) + 4) + 1)

View File

@ -35,10 +35,11 @@ struct bt_mesh_health_cli {
};
extern const struct bt_mesh_model_op bt_mesh_health_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_health_cli_cb;
#define BT_MESH_MODEL_HEALTH_CLI(cli_data) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_HEALTH_CLI, \
bt_mesh_health_cli_op, NULL, cli_data)
#define BT_MESH_MODEL_HEALTH_CLI(cli_data) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_op, \
NULL, cli_data, &bt_mesh_health_cli_cb)
int bt_mesh_health_cli_set(struct bt_mesh_model *model);

View File

@ -71,6 +71,7 @@ struct bt_mesh_health_srv {
int bt_mesh_fault_update(struct bt_mesh_elem *elem);
extern const struct bt_mesh_model_op bt_mesh_health_srv_op[];
extern const struct bt_mesh_model_cb bt_mesh_health_srv_cb;
/** @def BT_MESH_MODEL_HEALTH_SRV
*
@ -84,9 +85,9 @@ extern const struct bt_mesh_model_op bt_mesh_health_srv_op[];
*
* @return New mesh model instance.
*/
#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_HEALTH_SRV, \
bt_mesh_health_srv_op, pub, srv)
#define BT_MESH_MODEL_HEALTH_SRV(srv, pub) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_op, \
pub, srv, &bt_mesh_health_srv_cb)
#ifdef __cplusplus
}

View File

@ -128,6 +128,28 @@ struct bt_mesh_prov {
*/
int (*input)(bt_mesh_input_action_t act, u8_t size);
/** @brief The other device finished their OOB input.
*
* This callback notifies the application that it should stop
* displaying its output OOB value, as the other party finished their
* OOB input.
*/
void (*input_complete)(void);
/** @brief Unprovisioned beacon has been received.
*
* This callback notifies the application that an unprovisioned
* beacon has been received.
*
* @param uuid UUID
* @param oob_info OOB Information
* @param uri_hash Pointer to URI Hash value. NULL if no hash was
* present in the beacon.
*/
void (*unprovisioned_beacon)(u8_t uuid[16],
bt_mesh_prov_oob_info_t oob_info,
u32_t *uri_hash);
/** @brief Provisioning link has been opened.
*
* This callback notifies the application that a provisioning
@ -157,6 +179,18 @@ struct bt_mesh_prov {
*/
void (*complete)(u16_t net_idx, u16_t addr);
/** @brief A new node has been added to the provisioning database.
*
* This callback notifies the application that provisioning has
* been successfully completed, and that a node has been assigned
* the specified NetKeyIndex and primary element address.
*
* @param net_idx NetKeyIndex given during provisioning.
* @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);
/** @brief Node has been reset.
*
* This callback notifies the application that the local node
@ -321,6 +355,19 @@ 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]);
/** @brief Provision a Mesh Node using PB-ADV
*
* @param uuid UUID
* @param net_idx Network Key Index
* @param addr Address to assign to remote device. If addr is 0, the lowest
* available address will be chosen.
* @param attention_duration The attention duration to be send to remote device
*
* @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);
/** @brief Check if the local node has been provisioned.
*
* This API can be used to check if the local node has been provisioned

View File

@ -19,20 +19,19 @@ struct bt_mesh_gen_model_cli {
void *op_param;
};
extern struct bt_mesh_gen_model_cli gen_onoff_cli;
extern const struct bt_mesh_model_op gen_onoff_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_gen_onoff_cli_cb;
#define BT_MESH_MODEL_GEN_ONOFF_CLI() \
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, \
gen_onoff_cli_op, NULL, &gen_onoff_cli)
#define BT_MESH_MODEL_GEN_ONOFF_CLI(cli_data, pub) \
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_ONOFF_CLI, gen_onoff_cli_op, pub,\
cli_data, &bt_mesh_gen_onoff_cli_cb)
extern struct bt_mesh_gen_model_cli gen_level_cli;
extern const struct bt_mesh_model_op gen_level_cli_op[];
extern const struct bt_mesh_model_cb bt_mesh_gen_level_cli_cb;
#define BT_MESH_MODEL_GEN_LEVEL_CLI(pub) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_CLI, \
gen_level_cli_op, NULL, &gen_level_cli)
#define BT_MESH_MODEL_GEN_LEVEL_CLI(cli_data, pub) \
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);
@ -42,7 +41,6 @@ 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_model_cli_init(struct bt_mesh_model *model, bool primary);
#ifdef __cplusplus
}

View File

@ -11,43 +11,54 @@
extern "C" {
#endif
struct bt_mesh_gen_onoff_srv_cb {
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);
};
extern const struct bt_mesh_model_op gen_onoff_srv_op[];
extern const struct bt_mesh_model_cb gen_onoff_srv_cb;
#define BT_MESH_MODEL_GEN_ONOFF_SRV(srv, pub) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, \
gen_onoff_srv_op, pub, srv)
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_ONOFF_SRV, \
gen_onoff_srv_op, pub, srv, &gen_onoff_srv_cb)
struct bt_mesh_gen_level_srv {
struct bt_mesh_model *model;
struct bt_mesh_gen_level_srv_cb {
int (*get)(struct bt_mesh_model *model, s16_t *level);
int (*set)(struct bt_mesh_model *model, s16_t level);
};
extern const struct bt_mesh_model_op gen_level_srv_op[];
extern const struct bt_mesh_model_cb gen_level_srv_cb;
#define BT_MESH_MODEL_GEN_LEVEL_SRV(srv, pub) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, \
gen_level_srv_op, pub, srv)
BT_MESH_MODEL_CB(BT_MESH_MODEL_ID_GEN_LEVEL_SRV, \
gen_level_srv_op, pub, srv, &gen_level_srv_cb)
struct bt_mesh_light_lightness_srv {
struct bt_mesh_model *model;
struct bt_mesh_light_lightness_srv_cb {
int (*get)(struct bt_mesh_model *model, s16_t *level);
int (*set)(struct bt_mesh_model *model, s16_t level);
};
extern const struct bt_mesh_model_op light_lightness_srv_op[];
extern const struct bt_mesh_model_cb light_lightness_srv_cb;
#define BT_MESH_MODEL_LIGHT_LIGHTNESS_SRV(srv, pub) \
BT_MESH_MODEL(BT_MESH_MODEL_ID_LIGHT_LIGHTNESS_SRV, \
light_lightness_srv_op, pub, srv)
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(struct bt_mesh_gen_onoff_srv_cb *gen_onoff_cb);
void bt_mesh_set_gen_level_srv_cb(struct bt_mesh_gen_level_srv_cb *gen_level_cb);
void bt_mesh_set_light_lightness_srv_cb(struct bt_mesh_light_lightness_srv_cb *light_lightness_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));
#ifdef __cplusplus
}

View File

@ -73,13 +73,19 @@ struct ble_mbuf_hdr_rxinfo
/* XXX: we could just use single phy_mode field */
int8_t phy;
uint8_t phy_mode;
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY)
int8_t rpa_index;
#endif
#if MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_EXT_ADV)
void *user_data;
#endif
};
/* Flag definitions for rxinfo */
#define BLE_MBUF_HDR_F_IGNORED (0x8000)
#define BLE_MBUF_HDR_F_SCAN_REQ_TXD (0x4000)
#define BLE_MBUF_HDR_F_INITA_RESOLVED (0x2000)
#define BLE_MBUF_HDR_F_TARGETA_RESOLVED (0x2000)
#define BLE_MBUF_HDR_F_EXT_ADV_SEC (0x1000)
#define BLE_MBUF_HDR_F_EXT_ADV (0x0800)
#define BLE_MBUF_HDR_F_RESOLVED (0x0400)
@ -89,7 +95,7 @@ struct ble_mbuf_hdr_rxinfo
#define BLE_MBUF_HDR_F_DEVMATCH (0x0040)
#define BLE_MBUF_HDR_F_MIC_FAILURE (0x0020)
#define BLE_MBUF_HDR_F_SCAN_RSP_TXD (0x0010)
#define BLE_MBUF_HDR_F_SCAN_RSP_CHK (0x0008)
#define BLE_MBUF_HDR_F_SCAN_RSP_RXD (0x0008)
#define BLE_MBUF_HDR_F_RXSTATE_MASK (0x0007)
/* Transmit info. NOTE: no flags defined */
@ -111,6 +117,12 @@ struct ble_mbuf_hdr
uint32_t rem_usecs;
};
#define BLE_MBUF_HDR_IGNORED(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_IGNORED))
#define BLE_MBUF_HDR_SCAN_REQ_TXD(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_REQ_TXD))
#define BLE_MBUF_HDR_EXT_ADV_SEC(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_EXT_ADV_SEC))
@ -120,8 +132,8 @@ struct ble_mbuf_hdr
#define BLE_MBUF_HDR_DEVMATCH(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_DEVMATCH))
#define BLE_MBUF_HDR_SCAN_RSP_RCV(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_CHK))
#define BLE_MBUF_HDR_SCAN_RSP_RXD(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_SCAN_RSP_RXD))
#define BLE_MBUF_HDR_AUX_INVALID(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_AUX_INVALID))
@ -141,6 +153,9 @@ struct ble_mbuf_hdr
#define BLE_MBUF_HDR_INITA_RESOLVED(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_INITA_RESOLVED))
#define BLE_MBUF_HDR_TARGETA_RESOLVED(hdr) \
(!!((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_TARGETA_RESOLVED))
#define BLE_MBUF_HDR_RX_STATE(hdr) \
((uint8_t)((hdr)->rxinfo.flags & BLE_MBUF_HDR_F_RXSTATE_MASK))
@ -235,11 +250,10 @@ enum ble_error_codes
BLE_ERR_UNK_ADV_INDENT = 0x42,
BLE_ERR_LIMIT_REACHED = 0x43,
BLE_ERR_OPERATION_CANCELLED = 0x44,
BLE_ERR_PACKET_TOO_LONG = 0x45,
BLE_ERR_MAX = 0xff
};
int ble_err_from_os(int os_err);
/* HW error codes */
#define BLE_HW_ERR_DO_NOT_USE (0) /* XXX: reserve this one for now */
#define BLE_HW_ERR_HCI_SYNC_LOSS (1)

File diff suppressed because it is too large Load Diff

View File

@ -6,14 +6,13 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <os/os_mbuf.h>
#include "mesh/mesh.h"
#include "syscfg/syscfg.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_ACCESS))
#include "host/ble_hs_log.h"
#define MESH_LOG_MODULE BLE_MESH_ACCESS_LOG
#include <errno.h>
#include <os/os_mbuf.h>
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "adv.h"
@ -29,24 +28,6 @@
static const struct bt_mesh_comp *dev_comp;
static u16_t dev_primary_addr;
static const struct {
const u16_t id;
int (*const init)(struct bt_mesh_model *model, bool primary);
} model_init[] = {
{ BT_MESH_MODEL_ID_CFG_SRV, bt_mesh_cfg_srv_init },
{ BT_MESH_MODEL_ID_HEALTH_SRV, bt_mesh_health_srv_init },
#if MYNEWT_VAL(BLE_MESH_CFG_CLI)
{ BT_MESH_MODEL_ID_CFG_CLI, bt_mesh_cfg_cli_init },
#endif
#if MYNEWT_VAL(BLE_MESH_HEALTH_CLI)
{ BT_MESH_MODEL_ID_HEALTH_CLI, bt_mesh_health_cli_init },
#endif
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
{ BT_MESH_MODEL_ID_GEN_ONOFF_CLI, bt_mesh_gen_model_cli_init },
{ BT_MESH_MODEL_ID_GEN_LEVEL_CLI, bt_mesh_gen_model_cli_init },
#endif
};
void bt_mesh_model_foreach(void (*func)(struct bt_mesh_model *mod,
struct bt_mesh_elem *elem,
bool vnd, bool primary,
@ -101,7 +82,11 @@ s32_t bt_mesh_model_pub_period_get(struct bt_mesh_model *mod)
CODE_UNREACHABLE;
}
return period >> mod->pub->period_div;
if (mod->pub->fast_period) {
return period >> mod->pub->period_div;
} else {
return period;
}
}
static s32_t next_period(struct bt_mesh_model *mod)
@ -146,7 +131,24 @@ static void publish_sent(int err, void *user_data)
}
}
static void publish_start(u16_t duration, int err, void *user_data)
{
struct bt_mesh_model *mod = user_data;
struct bt_mesh_model_pub *pub = mod->pub;
if (err) {
BT_ERR("Failed to publish: err %d", err);
return;
}
/* Initialize the timestamp for the beginning of a new period */
if (pub->count == BT_MESH_PUB_TRANSMIT_COUNT(pub->retransmit)) {
pub->period_start = k_uptime_get_32();
}
}
static const struct bt_mesh_send_cb pub_sent_cb = {
.start = publish_start,
.end = publish_sent,
};
@ -223,8 +225,6 @@ static void mod_publish(struct ble_npl_event *work)
__ASSERT_NO_MSG(pub->update != NULL);
pub->period_start = k_uptime_get_32();
err = pub->update(pub->mod);
if (err) {
BT_ERR("Failed to update publication message");
@ -235,11 +235,6 @@ static void mod_publish(struct ble_npl_event *work)
if (err) {
BT_ERR("Publishing failed (err %d)", err);
}
if (pub->count) {
/* Retransmissions also control the timer */
k_delayed_work_cancel(&pub->timer);
}
}
struct bt_mesh_elem *bt_mesh_model_elem(struct bt_mesh_model *mod)
@ -297,14 +292,8 @@ static void mod_init(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
mod->mod_idx = mod - elem->models;
}
if (vnd) {
return;
}
for (i = 0; i < ARRAY_SIZE(model_init); i++) {
if (model_init[i].id == mod->id) {
model_init[i].init(mod, primary);
}
if (mod->cb && mod->cb->init) {
mod->cb->init(mod);
}
}
@ -354,7 +343,7 @@ u16_t bt_mesh_primary_addr(void)
return dev_primary_addr;
}
u16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, u16_t addr)
static u16_t *model_group_get(struct bt_mesh_model *mod, u16_t addr)
{
int i;
@ -367,6 +356,45 @@ u16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, u16_t addr)
return NULL;
}
struct find_group_visitor_ctx {
u16_t *entry;
struct bt_mesh_model *mod;
u16_t addr;
};
static enum bt_mesh_walk find_group_mod_visitor(struct bt_mesh_model *mod,
u32_t depth, void *user_data)
{
struct find_group_visitor_ctx *ctx = user_data;
if (mod->elem_idx != ctx->mod->elem_idx) {
return BT_MESH_WALK_CONTINUE;
}
ctx->entry = model_group_get(mod, ctx->addr);
if (ctx->entry) {
ctx->mod = mod;
return BT_MESH_WALK_STOP;
}
return BT_MESH_WALK_CONTINUE;
}
u16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, u16_t addr)
{
struct find_group_visitor_ctx ctx = {
.mod = *mod,
.entry = NULL,
.addr = addr,
};
bt_mesh_model_tree_walk(bt_mesh_model_root(*mod),
find_group_mod_visitor, &ctx);
*mod = ctx.mod;
return ctx.entry;
}
static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
u16_t group_addr)
{
@ -377,7 +405,7 @@ static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
for (i = 0; i < elem->model_count; i++) {
model = &elem->models[i];
match = bt_mesh_model_find_group(model, group_addr);
match = model_group_get(model, group_addr);
if (match) {
return model;
}
@ -386,7 +414,7 @@ static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
for (i = 0; i < elem->vnd_model_count; i++) {
model = &elem->vnd_models[i];
match = bt_mesh_model_find_group(model, group_addr);
match = model_group_get(model, group_addr);
if (match) {
return model;
}
@ -397,17 +425,21 @@ static struct bt_mesh_model *bt_mesh_elem_find_group(struct bt_mesh_elem *elem,
struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr)
{
int i;
u16_t index;
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
if (BT_MESH_ADDR_IS_UNICAST(addr)) {
index = (addr - dev_comp->elem[0].addr);
if (index < dev_comp->elem_count) {
return &dev_comp->elem[index];
} else {
return NULL;
}
}
if (BT_MESH_ADDR_IS_GROUP(addr) ||
BT_MESH_ADDR_IS_VIRTUAL(addr)) {
if (bt_mesh_elem_find_group(elem, addr)) {
return elem;
}
} else if (elem->addr == addr) {
for (index = 0; index < dev_comp->elem_count; index++) {
struct bt_mesh_elem *elem = &dev_comp->elem[index];
if (bt_mesh_elem_find_group(elem, addr)) {
return elem;
}
}
@ -425,7 +457,9 @@ static bool model_has_key(struct bt_mesh_model *mod, u16_t key)
int i;
for (i = 0; i < ARRAY_SIZE(mod->keys); i++) {
if (mod->keys[i] == key) {
if (mod->keys[i] == key ||
(mod->keys[i] == BT_MESH_KEY_DEV_ANY &&
BT_MESH_IS_DEV_KEY(key))) {
return true;
}
}
@ -433,9 +467,19 @@ 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)
{
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 (mod->elem_idx == 0 && bt_mesh_fixed_group_match(dst));
}
static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models,
u8_t model_count, u16_t dst,
u16_t app_idx, u32_t opcode,
u8_t model_count, u32_t opcode,
struct bt_mesh_model **model)
{
u8_t i;
@ -445,17 +489,6 @@ static const struct bt_mesh_model_op *find_op(struct bt_mesh_model *models,
*model = &models[i];
if (BT_MESH_ADDR_IS_GROUP(dst) ||
BT_MESH_ADDR_IS_VIRTUAL(dst)) {
if (!bt_mesh_model_find_group(*model, dst)) {
continue;
}
}
if (!model_has_key(*model, app_idx)) {
continue;
}
for (op = (*model)->op; op->func; op++) {
if (op->opcode == opcode) {
return op;
@ -508,8 +541,7 @@ bool bt_mesh_fixed_group_match(u16_t addr)
case BT_MESH_ADDR_ALL_NODES:
return true;
case BT_MESH_ADDR_PROXIES:
/* TODO: Proxy not yet supported */
return false;
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:
@ -540,24 +572,13 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
for (i = 0; i < dev_comp->elem_count; i++) {
struct bt_mesh_elem *elem = &dev_comp->elem[i];
if (BT_MESH_ADDR_IS_UNICAST(rx->ctx.recv_dst)) {
if (elem->addr != rx->ctx.recv_dst) {
continue;
}
} else if (BT_MESH_ADDR_IS_GROUP(rx->ctx.recv_dst) ||
BT_MESH_ADDR_IS_VIRTUAL(rx->ctx.recv_dst)) {
/* find_op() will do proper model/group matching */
} else if (i != 0 ||
!bt_mesh_fixed_group_match(rx->ctx.recv_dst)) {
continue;
}
struct net_buf_simple_state state;
/* SIG models cannot contain 3-byte (vendor) OpCodes, and
* vendor models cannot contain SIG (1- or 2-byte) OpCodes, so
* we only need to do the lookup in one of the model lists.
*/
if (opcode < 0x10000) {
if (BT_MESH_MODEL_OP_LEN(opcode) < 3) {
models = elem->models;
count = elem->model_count;
} else {
@ -565,29 +586,32 @@ void bt_mesh_model_recv(struct bt_mesh_net_rx *rx, struct os_mbuf *buf)
count = elem->vnd_model_count;
}
op = find_op(models, count, rx->ctx.recv_dst, rx->ctx.app_idx,
opcode, &model);
if (op) {
struct net_buf_simple_state state;
op = find_op(models, count, opcode, &model);
if (!op) {
BT_DBG("No OpCode 0x%08x for elem %d", opcode, i);
continue;
}
if (buf->om_len < op->min_len) {
BT_ERR("Too short message for OpCode 0x%08x",
(unsigned) opcode);
if (!model_has_key(model, rx->ctx.app_idx)) {
continue;
}
/* The callback will likely parse the buffer, so
* store the parsing state in case multiple models
* receive the message.
*/
net_buf_simple_save(buf, &state);
op->func(model, &rx->ctx, buf);
net_buf_simple_restore(buf, &state);
} else {
BT_DBG("No OpCode 0x%08x for elem %d",
(unsigned) opcode, i);
if (!model_has_dst(model, rx->ctx.recv_dst)) {
continue;
}
if (buf->om_len < op->min_len) {
BT_ERR("Too short message for OpCode 0x%08x", opcode);
continue;
}
/* The callback will likely parse the buffer, so
* store the parsing state in case multiple models
* receive the message.
*/
net_buf_simple_save(buf, &state);
op->func(model, &rx->ctx, buf);
net_buf_simple_restore(buf, &state);
}
}
@ -595,21 +619,21 @@ void bt_mesh_model_msg_init(struct os_mbuf *msg, u32_t opcode)
{
net_buf_simple_init(msg, 0);
if (opcode < 0x100) {
/* 1-byte OpCode */
switch (BT_MESH_MODEL_OP_LEN(opcode)) {
case 1:
net_buf_simple_add_u8(msg, opcode);
return;
}
if (opcode < 0x10000) {
/* 2-byte OpCode */
break;
case 2:
net_buf_simple_add_be16(msg, opcode);
return;
break;
case 3:
net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff));
net_buf_simple_add_le16(msg, opcode & 0xffff);
break;
default:
BT_WARN("Unknown opcode format");
break;
}
/* 3-byte OpCode */
net_buf_simple_add_u8(msg, ((opcode >> 16) & 0xff));
net_buf_simple_add_le16(msg, opcode & 0xffff);
}
static int model_send(struct bt_mesh_model *model,
@ -732,7 +756,7 @@ done:
return err;
}
struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem,
struct bt_mesh_model *bt_mesh_model_find_vnd(const struct bt_mesh_elem *elem,
u16_t company, u16_t id)
{
u8_t i;
@ -747,7 +771,7 @@ struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem,
return NULL;
}
struct bt_mesh_model *bt_mesh_model_find(struct bt_mesh_elem *elem,
struct bt_mesh_model *bt_mesh_model_find(const struct bt_mesh_elem *elem,
u16_t id)
{
u8_t i;
@ -765,3 +789,68 @@ const struct bt_mesh_comp *bt_mesh_comp_get(void)
{
return dev_comp;
}
struct bt_mesh_model *bt_mesh_model_root(struct bt_mesh_model *mod)
{
#ifdef CONFIG_BT_MESH_MODEL_EXTENSIONS
while (mod->next) {
mod = mod->next;
}
#endif
return 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,
void *user_data),
void *user_data)
{
struct bt_mesh_model *m = root;
u32_t depth = 0;
do {
if (cb(m, depth, user_data) == BT_MESH_WALK_STOP) {
return;
}
#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS)
if (m->extends) {
m = m->extends;
depth++;
} else if (m->flags & BT_MESH_MOD_NEXT_IS_PARENT) {
m = m->next->next;
depth--;
} else {
m = m->next;
}
#endif
} while (m && m != root);
}
#if MYNEWT_VAL(BLE_MESH_MODEL_EXTENSIONS)
int bt_mesh_model_extend(struct bt_mesh_model *mod,
struct bt_mesh_model *base_mod)
{
/* Form a cyclical LCRS tree:
* The extends-pointer points to the first child, and the next-pointer
* points to the next sibling. The last sibling is marked by the
* BT_MESH_MOD_NEXT_IS_PARENT flag, and its next-pointer points back to
* the parent. This way, the whole tree is accessible from any node.
*
* We add children (extend them) by inserting them as the first child.
*/
if (base_mod->next) {
return -EALREADY;
}
if (mod->extends) {
base_mod->next = mod->extends;
} else {
base_mod->next = mod;
base_mod->flags |= BT_MESH_MOD_NEXT_IS_PARENT;
}
mod->extends = base_mod;
return 0;
}
#endif

View File

@ -16,6 +16,14 @@ 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),
};
/* Tree walk return codes */
enum bt_mesh_walk {
BT_MESH_WALK_STOP,
BT_MESH_WALK_CONTINUE,
};
void bt_mesh_elem_register(struct bt_mesh_elem *elem, u8_t count);
@ -25,12 +33,14 @@ u8_t bt_mesh_elem_count(void);
/* Find local element based on unicast or group address */
struct bt_mesh_elem *bt_mesh_elem_find(u16_t addr);
struct bt_mesh_model *bt_mesh_model_find_vnd(struct bt_mesh_elem *elem,
u16_t company, u16_t id);
struct bt_mesh_model * bt_mesh_model_find(struct bt_mesh_elem *elem,
u16_t id);
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,
void *user_data),
void *user_data);
u16_t *bt_mesh_model_find_group(struct bt_mesh_model *mod, u16_t addr);
u16_t *bt_mesh_model_find_group(struct bt_mesh_model **mod, u16_t addr);
bool bt_mesh_fixed_group_match(u16_t addr);

View File

@ -7,12 +7,10 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "mesh/mesh.h"
#include "syscfg/syscfg.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_ADV))
#include "host/ble_hs_log.h"
#define MESH_LOG_MODULE BLE_MESH_ADV_LOG
#include "mesh/mesh.h"
#include "host/ble_hs_adv.h"
#include "host/ble_gap.h"
#include "nimble/hci_common.h"
@ -108,9 +106,14 @@ static inline void adv_send(struct os_mbuf *buf)
adv_int = max(adv_int_min,
BT_MESH_TRANSMIT_INT(BT_MESH_ADV(buf)->xmit));
#if MYNEWT_VAL(BLE_CONTROLLER)
duration = ((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) *
(adv_int + 10));
#else
duration = (MESH_SCAN_WINDOW_MS +
((BT_MESH_TRANSMIT_COUNT(BT_MESH_ADV(buf)->xmit) + 1) *
(adv_int + 10)));
#endif
BT_DBG("type %u om_len %u: %s", BT_MESH_ADV(buf)->type,
buf->om_len, bt_hex(buf->om_data, buf->om_len));
@ -188,6 +191,8 @@ mesh_adv_thread(void *args)
if (BT_MESH_ADV(buf)->busy) {
BT_MESH_ADV(buf)->busy = 0;
adv_send(buf);
} else {
net_buf_unref(buf);
}
/* os_sched(NULL); */
@ -395,6 +400,8 @@ done:
int bt_mesh_scan_enable(void)
{
int err;
#if MYNEWT_VAL(BLE_EXT_ADV)
struct ble_gap_ext_disc_params uncoded_params =
{ .itvl = MESH_SCAN_INTERVAL, .window = MESH_SCAN_WINDOW,
@ -402,7 +409,7 @@ int bt_mesh_scan_enable(void)
BT_DBG("");
return ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0,
err = ble_gap_ext_disc(g_mesh_addr_type, 0, 0, 0, 0, 0,
&uncoded_params, NULL, NULL, NULL);
#else
struct ble_gap_disc_params scan_param =
@ -411,13 +418,28 @@ int bt_mesh_scan_enable(void)
BT_DBG("");
return ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param, NULL, NULL);
err = ble_gap_disc(g_mesh_addr_type, BLE_HS_FOREVER, &scan_param,
NULL, NULL);
#endif
if (err && err != BLE_HS_EALREADY) {
BT_ERR("starting scan failed (err %d)", err);
return err;
}
return 0;
}
int bt_mesh_scan_disable(void)
{
int err;
BT_DBG("");
return ble_gap_disc_cancel();
err = ble_gap_disc_cancel();
if (err && err != BLE_HS_EALREADY) {
BT_ERR("stopping scan failed (err %d)", err);
return err;
}
return 0;
}

View File

@ -42,15 +42,12 @@ struct bt_mesh_adv {
busy:1;
u8_t xmit;
union {
/* Address, used e.g. for Friend Queue messages */
u16_t addr;
/* For transport layer segment sending */
struct {
u8_t attempts;
} seg;
/* For transport layer segment sending */
struct {
u8_t attempts;
} seg;
};
u8_t flags;
int ref_cnt;
struct ble_npl_event ev;

View File

@ -6,15 +6,14 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_BEACON_LOG
#include <errno.h>
#include <assert.h>
#include "os/os_mbuf.h"
#include "mesh/mesh.h"
#include "syscfg/syscfg.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_BEACON))
#include "host/ble_hs_log.h"
#include "adv.h"
#include "mesh_priv.h"
#include "net.h"
@ -147,7 +146,6 @@ static int secure_beacon_send(void)
static int unprovisioned_beacon_send(void)
{
#if (MYNEWT_VAL(BLE_MESH_PB_ADV))
const struct bt_mesh_prov *prov;
u8_t uri_hash[16] = { 0 };
struct os_mbuf *buf;
@ -199,10 +197,43 @@ static int unprovisioned_beacon_send(void)
net_buf_unref(buf);
}
#endif /* MYNEWT_VAL(BLE_MESH_PB_ADV) */
return 0;
}
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;
if (buf->om_len != 18 && buf->om_len != 22) {
BT_ERR("Invalid unprovisioned beacon length (%u)", buf->om_len);
return;
}
uuid = net_buf_simple_pull_mem(buf, 16);
oob_info = net_buf_simple_pull_be16(buf);
if (buf->om_len == 4) {
uri_hash_val = net_buf_simple_pull_be32(buf);
uri_hash = &uri_hash_val;
}
BT_DBG("uuid %s", bt_hex(uuid, 16));
prov = bt_mesh_prov_get();
if (prov->unprovisioned_beacon) {
prov->unprovisioned_beacon(uuid,
(bt_mesh_prov_oob_info_t)oob_info,
uri_hash);
}
#endif
}
static void update_beacon_observation(void)
{
static bool first_half;
@ -249,11 +280,10 @@ static void beacon_send(struct ble_npl_event *work)
k_delayed_work_submit(&beacon_timer,
PROVISIONED_INTERVAL);
}
} else {
} else if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
unprovisioned_beacon_send();
k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL);
}
}
static void secure_beacon_recv(struct os_mbuf *buf)
@ -351,7 +381,7 @@ void bt_mesh_beacon_recv(struct os_mbuf *buf)
type = net_buf_simple_pull_u8(buf);
switch (type) {
case BEACON_TYPE_UNPROVISIONED:
BT_DBG("Ignoring unprovisioned device beacon");
unprovisioned_beacon_recv(buf);
break;
case BEACON_TYPE_SECURE:
secure_beacon_recv(buf);

View File

@ -7,9 +7,9 @@
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG
#if MYNEWT_VAL(BLE_MESH_CFG_CLI)
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_MODEL))
#include "mesh/mesh.h"
#include <string.h>
@ -21,6 +21,9 @@
#define CID_NVAL 0xffff
/* 2 byte dummy opcode for getting compile time buffer sizes. */
#define DUMMY_2_BYTE_OP BT_MESH_MODEL_OP_2(0xff, 0xff)
struct comp_data {
u8_t *status;
struct os_mbuf *comp;
@ -481,6 +484,38 @@ const struct bt_mesh_model_op bt_mesh_cfg_cli_op[] = {
BT_MESH_MODEL_OP_END,
};
static int cfg_cli_init(struct bt_mesh_model *model)
{
BT_DBG("");
if (!bt_mesh_model_in_primary(model)) {
BT_ERR("Configuration Client only allowed in primary element");
return -EINVAL;
}
if (!model->user_data) {
BT_ERR("No Configuration Client context provided");
return -EINVAL;
}
cli = model->user_data;
cli->model = model;
/*
* Configuration Model security is device-key based and both the local
* and remote keys are allowed to access this model.
*/
model->keys[0] = BT_MESH_KEY_DEV_ANY;
k_sem_init(&cli->op_sync, 0, 1);
return 0;
}
const struct bt_mesh_model_cb bt_mesh_cfg_cli_cb = {
.init = cfg_cli_init,
};
static int cli_prepare(void *param, u32_t op)
{
if (!cli) {
@ -519,10 +554,10 @@ static int cli_wait(void)
int bt_mesh_cfg_comp_data_get(u16_t net_idx, u16_t addr, u8_t page,
u8_t *status, struct os_mbuf *comp)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEV_COMP_DATA_GET, 1);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -556,10 +591,10 @@ done:
static int get_state_u8(u16_t net_idx, u16_t addr, u32_t op, u32_t rsp,
u8_t *val)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 0);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -588,10 +623,10 @@ done:
static int set_state_u8(u16_t net_idx, u16_t addr, u32_t op, u32_t rsp,
u8_t new_val, u8_t *val)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 1);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -670,10 +705,10 @@ int bt_mesh_cfg_gatt_proxy_set(u16_t net_idx, u16_t addr, u8_t val,
int bt_mesh_cfg_relay_get(u16_t net_idx, u16_t addr, u8_t *status,
u8_t *transmit)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_GET, 0);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -706,10 +741,10 @@ done:
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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_SET, 2);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -744,10 +779,10 @@ done:
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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 18 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_ADD, 18);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -788,10 +823,10 @@ 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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(1 + 19 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_ADD, 19);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -833,10 +868,10 @@ static int mod_app_bind(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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 8 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_BIND, 8);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -904,10 +939,10 @@ int bt_mesh_cfg_mod_app_bind_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
static int mod_sub(u32_t op, 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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 8 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 8);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -1014,10 +1049,10 @@ static int mod_sub_va(u32_t op, 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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 22 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(DUMMY_2_BYTE_OP, 22);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -1133,10 +1168,10 @@ static int mod_pub_get(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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 6 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_GET, 6);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -1205,10 +1240,10 @@ static int mod_pub_set(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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 13 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_SET, 13);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -1230,7 +1265,7 @@ static int mod_pub_set(u16_t net_idx, u16_t addr, u16_t elem_addr,
net_buf_simple_add_le16(msg, elem_addr);
net_buf_simple_add_le16(msg, pub->addr);
net_buf_simple_add_le16(msg, (pub->app_idx & (pub->cred_flag << 12)));
net_buf_simple_add_le16(msg, (pub->app_idx | (pub->cred_flag << 12)));
net_buf_simple_add_u8(msg, pub->ttl);
net_buf_simple_add_u8(msg, pub->period);
net_buf_simple_add_u8(msg, pub->transmit);
@ -1281,10 +1316,10 @@ int bt_mesh_cfg_mod_pub_set_vnd(u16_t net_idx, u16_t addr, u16_t elem_addr,
int bt_mesh_cfg_hb_sub_set(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_sub *sub, u8_t *status)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_SET, 5);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -1325,10 +1360,10 @@ done:
int bt_mesh_cfg_hb_sub_get(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_sub *sub, u8_t *status)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_GET, 0);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -1366,10 +1401,10 @@ done:
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)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_SET, 9);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
.app_idx = BT_MESH_KEY_DEV_REMOTE,
.addr = addr,
.send_ttl = BT_MESH_TTL_DEFAULT,
};
@ -1412,7 +1447,7 @@ done:
int bt_mesh_cfg_hb_pub_get(u16_t net_idx, u16_t addr,
struct bt_mesh_cfg_hb_pub *pub, u8_t *status)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_GET, 0);
struct bt_mesh_msg_ctx ctx = {
.net_idx = net_idx,
.app_idx = BT_MESH_KEY_DEV,
@ -1460,29 +1495,4 @@ void bt_mesh_cfg_cli_timeout_set(s32_t timeout)
msg_timeout = timeout;
}
int bt_mesh_cfg_cli_init(struct bt_mesh_model *model, bool primary)
{
BT_DBG("primary %u", primary);
if (!primary) {
BT_ERR("Configuration Client only allowed in primary element");
return -EINVAL;
}
if (!model->user_data) {
BT_ERR("No Configuration Client context provided");
return -EINVAL;
}
cli = model->user_data;
cli->model = model;
/* Configuration Model security is device-key based */
model->keys[0] = BT_MESH_KEY_DEV;
k_sem_init(&cli->op_sync, 0, 1);
return 0;
}
#endif

View File

@ -6,16 +6,15 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include "mesh/mesh.h"
#include "syscfg/syscfg.h"
#define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_MODEL)
#include "host/ble_hs_log.h"
#include "mesh_priv.h"
#include "adv.h"
#include "net.h"
@ -34,61 +33,7 @@
static struct bt_mesh_cfg_srv *conf;
static struct label {
u16_t ref;
u16_t addr;
u8_t uuid[16];
} labels[MYNEWT_VAL(BLE_MESH_LABEL_COUNT)];
static void hb_send(struct bt_mesh_model *model)
{
struct bt_mesh_cfg_srv *cfg = model->user_data;
u16_t feat = 0;
struct __packed {
u8_t init_ttl;
u16_t feat;
} hb;
struct bt_mesh_msg_ctx ctx = {
.net_idx = cfg->hb_pub.net_idx,
.app_idx = BT_MESH_KEY_UNUSED,
.addr = cfg->hb_pub.dst,
.send_ttl = cfg->hb_pub.ttl,
};
struct bt_mesh_net_tx tx = {
.sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx),
.ctx = &ctx,
.src = bt_mesh_model_elem(model)->addr,
.xmit = bt_mesh_net_transmit_get(),
};
hb.init_ttl = cfg->hb_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 (MYNEWT_VAL(BLE_MESH_LOW_POWER))
if (bt_mesh.lpn.state != BT_MESH_LPN_DISABLED) {
feat |= BT_MESH_FEAT_LOW_POWER;
}
#endif
hb.feat = sys_cpu_to_be16(feat);
BT_DBG("InitTTL %u feat 0x%04x", cfg->hb_pub.ttl, feat);
bt_mesh_ctl_send(&tx, TRANS_CTL_OP_HEARTBEAT, &hb, sizeof(hb),
NULL, NULL, NULL);
}
static struct label labels[CONFIG_BT_MESH_LABEL_COUNT];
static int comp_add_elem(struct os_mbuf *buf, struct bt_mesh_elem *elem,
bool primary)
@ -175,9 +120,9 @@ static void dev_comp_data_get(struct bt_mesh_model *model,
bt_hex(buf->om_data, buf->om_len));
page = net_buf_simple_pull_u8(buf);
if (page != 0) {
BT_WARN("Composition page %u not available", page);
page = 0;
if (page != 0U) {
BT_DBG("Composition page %u not available", page);
page = 0U;
}
bt_mesh_model_msg_init(sdu, OP_DEV_COMP_DATA_STATUS);
@ -481,7 +426,7 @@ static void app_key_add(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_STATUS, 4);
u16_t key_net_idx, key_app_idx;
u8_t status;
@ -508,7 +453,7 @@ static void app_key_update(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_STATUS, 4);
u16_t key_net_idx, key_app_idx;
u8_t status;
@ -564,7 +509,7 @@ static void app_key_del(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_APP_KEY_STATUS, 4);
u16_t key_net_idx, key_app_idx;
struct bt_mesh_app_key *key;
u8_t status;
@ -617,8 +562,8 @@ static void app_key_get(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct os_mbuf *msg =
NET_BUF_SIMPLE(2 + 3 + 4 +
IDX_LEN(MYNEWT_VAL(BLE_MESH_APP_KEY_COUNT)));
BT_MESH_MODEL_BUF(OP_APP_KEY_LIST,
3 + IDX_LEN(CONFIG_BT_MESH_APP_KEY_COUNT));
u16_t get_idx, i, prev;
u8_t status;
@ -679,8 +624,7 @@ static void beacon_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_BEACON_STATUS, 1);
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,
@ -699,8 +643,7 @@ static void beacon_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_BEACON_STATUS, 1);
struct bt_mesh_cfg_srv *cfg = model->user_data;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
@ -744,8 +687,7 @@ static void default_ttl_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEFAULT_TTL_STATUS, 1);
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,
@ -766,8 +708,7 @@ static void default_ttl_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_DEFAULT_TTL_STATUS, 1);
struct bt_mesh_cfg_srv *cfg = model->user_data;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
@ -803,8 +744,7 @@ done:
static void send_gatt_proxy_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_GATT_PROXY_STATUS, 1);
bt_mesh_model_msg_init(msg, OP_GATT_PROXY_STATUS);
net_buf_simple_add_u8(msg, bt_mesh_gatt_proxy_get());
@ -833,7 +773,6 @@ static void gatt_proxy_set(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct bt_mesh_cfg_srv *cfg = model->user_data;
struct bt_mesh_subnet *sub;
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,
@ -866,33 +805,10 @@ static void gatt_proxy_set(struct bt_mesh_model *model,
bt_mesh_store_cfg();
}
if (cfg->gatt_proxy == BT_MESH_GATT_PROXY_DISABLED) {
int i;
/* Section 4.2.11.1: "When the GATT Proxy state is set to
* 0x00, the Node Identity state for all subnets shall be set
* to 0x00 and shall not be changed."
*/
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) {
bt_mesh_proxy_identity_stop(sub);
}
}
/* Section 4.2.11: "Upon transition from GATT Proxy state 0x01
* to GATT Proxy state 0x00 the GATT Bearer Server shall
* disconnect all GATT Bearer Clients.
*/
bt_mesh_proxy_gatt_disconnect();
}
bt_mesh_adv_update();
sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx);
if ((cfg->hb_pub.feat & BT_MESH_FEAT_PROXY) && sub) {
hb_send(model);
if (cfg->hb_pub.feat & BT_MESH_FEAT_PROXY) {
bt_mesh_heartbeat_send();
}
send_status:
@ -903,8 +819,7 @@ static void net_transmit_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_TRANSMIT_STATUS, 1);
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,
@ -925,8 +840,7 @@ static void net_transmit_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_TRANSMIT_STATUS, 1);
struct bt_mesh_cfg_srv *cfg = model->user_data;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
@ -961,8 +875,7 @@ static void relay_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_STATUS, 2);
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,
@ -984,8 +897,7 @@ static void relay_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_RELAY_STATUS, 2);
struct bt_mesh_cfg_srv *cfg = model->user_data;
BT_DBG("net_idx 0x%04x app_idx 0x%04x src 0x%04x len %u: %s",
@ -995,7 +907,6 @@ static void relay_set(struct bt_mesh_model *model,
if (!cfg) {
BT_WARN("No Configuration Server context available");
} else if (buf->om_data[0] == 0x00 || buf->om_data[0] == 0x01) {
struct bt_mesh_subnet *sub;
bool change;
if (cfg->relay == BT_MESH_RELAY_NOT_SUPPORTED) {
@ -1016,9 +927,8 @@ static void relay_set(struct bt_mesh_model *model,
BT_MESH_TRANSMIT_COUNT(cfg->relay_retransmit),
BT_MESH_TRANSMIT_INT(cfg->relay_retransmit));
sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx);
if ((cfg->hb_pub.feat & BT_MESH_FEAT_RELAY) && sub && change) {
hb_send(model);
if ((cfg->hb_pub.feat & BT_MESH_FEAT_RELAY) && change) {
bt_mesh_heartbeat_send();
}
} else {
BT_WARN("Invalid Relay value 0x%02x", buf->om_data[0]);
@ -1044,8 +954,7 @@ static void send_mod_pub_status(struct bt_mesh_model *cfg_mod,
bool vnd, struct bt_mesh_model *mod,
u8_t status, u8_t *mod_id)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 14 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_PUB_STATUS, 14);
bt_mesh_model_msg_init(msg, OP_MOD_PUB_STATUS);
@ -1188,25 +1097,61 @@ send_status:
status, mod_id);
}
#if MYNEWT_VAL(BLE_MESH_LABEL_COUNT) > 0
static u8_t va_add(u8_t *label_uuid, u16_t *addr)
struct label *get_label(u16_t index)
{
struct label *free_slot = NULL;
if (index >= ARRAY_SIZE(labels)) {
return NULL;
}
return &labels[index];
}
#if CONFIG_BT_MESH_LABEL_COUNT > 0
static inline void va_store(struct label *store)
{
atomic_set_bit(store->flags, BT_MESH_VA_CHANGED);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_label();
}
}
static struct label *va_find(const u8_t *label_uuid,
struct label **free_slot)
{
struct label *match = NULL;
int i;
if (free_slot != NULL) {
*free_slot = NULL;
}
for (i = 0; i < ARRAY_SIZE(labels); i++) {
if (!labels[i].ref) {
free_slot = &labels[i];
if (labels[i].ref == 0) {
if (free_slot != NULL) {
*free_slot = &labels[i];
}
continue;
}
if (!memcmp(labels[i].uuid, label_uuid, 16)) {
*addr = labels[i].addr;
labels[i].ref++;
return STATUS_SUCCESS;
match = &labels[i];
}
}
return match;
}
static u8_t va_add(u8_t *label_uuid, u16_t *addr)
{
struct label *update, *free_slot = NULL;
update = va_find(label_uuid, &free_slot);
if (update) {
update->ref++;
va_store(update);
return 0;
}
if (!free_slot) {
return STATUS_INSUFF_RESOURCES;
}
@ -1218,23 +1163,24 @@ static u8_t va_add(u8_t *label_uuid, u16_t *addr)
free_slot->ref = 1;
free_slot->addr = *addr;
memcpy(free_slot->uuid, label_uuid, 16);
va_store(free_slot);
return STATUS_SUCCESS;
}
static u8_t va_del(u8_t *label_uuid, u16_t *addr)
{
int i;
struct label *update;
for (i = 0; i < ARRAY_SIZE(labels); i++) {
if (!memcmp(labels[i].uuid, label_uuid, 16)) {
if (addr) {
*addr = labels[i].addr;
}
update = va_find(label_uuid, NULL);
if (update) {
update->ref--;
labels[i].ref--;
return STATUS_SUCCESS;
if (addr) {
*addr = update->addr;
}
va_store(update);
}
if (addr) {
@ -1244,28 +1190,36 @@ static u8_t va_del(u8_t *label_uuid, u16_t *addr)
return STATUS_CANNOT_REMOVE;
}
static void mod_sub_list_clear(struct bt_mesh_model *mod)
static size_t mod_sub_list_clear(struct bt_mesh_model *mod)
{
u8_t *label_uuid;
size_t clear_count;
int i;
/* Unref stored labels related to this model */
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (!BT_MESH_ADDR_IS_VIRTUAL(mod->groups[i])) {
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
mod->groups[i] = BT_MESH_ADDR_UNASSIGNED;
clear_count++;
}
continue;
}
label_uuid = bt_mesh_label_uuid_get(mod->groups[i]);
if (!label_uuid) {
BT_ERR("Label UUID not found");
continue;
}
va_del(label_uuid, NULL);
mod->groups[i] = BT_MESH_ADDR_UNASSIGNED;
clear_count++;
if (label_uuid) {
va_del(label_uuid, NULL);
} else {
BT_ERR("Label UUID not found");
}
}
/* Clear all subscriptions (0x0000 is the unassigned address) */
memset(mod->groups, 0, sizeof(mod->groups));
return clear_count;
}
static void mod_pub_va_set(struct bt_mesh_model *model,
@ -1300,8 +1254,7 @@ static void mod_pub_va_set(struct bt_mesh_model *model,
retransmit = net_buf_simple_pull_u8(buf);
mod_id = buf->om_data;
BT_DBG("elem_addr 0x%04x pub_addr 0x%04x cred_flag %u",
elem_addr, pub_addr, cred_flag);
BT_DBG("elem_addr 0x%04x cred_flag %u", elem_addr, cred_flag);
BT_DBG("pub_app_idx 0x%03x, pub_ttl %u pub_period 0x%02x",
pub_app_idx, pub_ttl, pub_period);
BT_DBG("retransmit 0x%02x (count %u interval %ums)", retransmit,
@ -1335,10 +1288,20 @@ send_status:
status, mod_id);
}
#else
static void mod_sub_list_clear(struct bt_mesh_model *mod)
static size_t mod_sub_list_clear(struct bt_mesh_model *mod)
{
/* Clear all subscriptions (0x0000 is the unassigned address) */
memset(mod->groups, 0, sizeof(mod->groups));
size_t clear_count;
int i;
/* Unref stored labels related to this model */
for (i = 0, clear_count = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
mod->groups[i] = BT_MESH_ADDR_UNASSIGNED;
clear_count++;
}
}
return clear_count;
}
static void mod_pub_va_set(struct bt_mesh_model *model,
@ -1395,8 +1358,7 @@ static void send_mod_sub_status(struct bt_mesh_model *model,
u16_t elem_addr, u16_t sub_addr, u8_t *mod_id,
bool vnd)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_SUB_STATUS, 9);
BT_DBG("status 0x%02x elem_addr 0x%04x sub_addr 0x%04x", status,
elem_addr, sub_addr);
@ -1429,8 +1391,8 @@ static void mod_sub_add(struct bt_mesh_model *model,
struct bt_mesh_elem *elem;
u8_t *mod_id;
u8_t status;
u16_t *entry;
bool vnd;
int i;
elem_addr = net_buf_simple_pull_le16(buf);
if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
@ -1463,33 +1425,31 @@ static void mod_sub_add(struct bt_mesh_model *model,
goto send_status;
}
if (bt_mesh_model_find_group(mod, sub_addr)) {
if (bt_mesh_model_find_group(&mod, sub_addr)) {
/* Tried to add existing subscription */
BT_DBG("found existing subscription");
status = STATUS_SUCCESS;
goto send_status;
}
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
mod->groups[i] = sub_addr;
break;
}
}
if (i == ARRAY_SIZE(mod->groups)) {
entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED);
if (!entry) {
status = STATUS_INSUFF_RESOURCES;
} else {
status = STATUS_SUCCESS;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
bt_mesh_lpn_group_add(sub_addr);
}
goto send_status;
}
*entry = sub_addr;
status = STATUS_SUCCESS;
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
bt_mesh_lpn_group_add(sub_addr);
}
send_status:
send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
mod_id, vnd);
@ -1547,7 +1507,7 @@ static void mod_sub_del(struct bt_mesh_model *model,
bt_mesh_lpn_group_del(&sub_addr, 1);
}
match = bt_mesh_model_find_group(mod, sub_addr);
match = bt_mesh_model_find_group(&mod, sub_addr);
if (match) {
*match = BT_MESH_ADDR_UNASSIGNED;
@ -1561,6 +1521,18 @@ send_status:
mod_id, vnd);
}
static enum bt_mesh_walk mod_sub_clear_visitor(struct bt_mesh_model *mod,
u32_t depth, void *user_data)
{
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
}
mod_sub_list_clear(mod);
return BT_MESH_WALK_CONTINUE;
}
static void mod_sub_overwrite(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
@ -1603,13 +1575,10 @@ static void mod_sub_overwrite(struct bt_mesh_model *model,
goto send_status;
}
if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
}
mod_sub_list_clear(mod);
if (ARRAY_SIZE(mod->groups) > 0) {
bt_mesh_model_tree_walk(bt_mesh_model_root(mod),
mod_sub_clear_visitor, NULL);
mod->groups[0] = sub_addr;
status = STATUS_SUCCESS;
@ -1665,11 +1634,8 @@ static void mod_sub_del_all(struct bt_mesh_model *model,
goto send_status;
}
if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
}
mod_sub_list_clear(mod);
bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_clear_visitor,
NULL);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
@ -1682,17 +1648,52 @@ send_status:
BT_MESH_ADDR_UNASSIGNED, mod_id, vnd);
}
struct mod_sub_list_ctx {
u16_t elem_idx;
struct os_mbuf *msg;
};
static enum bt_mesh_walk mod_sub_list_visitor(struct bt_mesh_model *mod,
u32_t depth, void *ctx)
{
struct mod_sub_list_ctx *visit = ctx;
int count = 0;
int i;
if (mod->elem_idx != visit->elem_idx) {
return BT_MESH_WALK_CONTINUE;
}
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
continue;
}
if (net_buf_simple_tailroom(visit->msg) <
2 + BT_MESH_MIC_SHORT) {
BT_WARN("No room for all groups");
return BT_MESH_WALK_STOP;
}
net_buf_simple_add_le16(visit->msg, mod->groups[i]);
count++;
}
BT_DBG("sublist: model %u:%x: %u groups", mod->elem_idx, mod->id,
count);
return BT_MESH_WALK_CONTINUE;
}
static void mod_sub_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg =
NET_BUF_SIMPLE(2 + 5 + 4 +
MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT) * 2);
struct os_mbuf *msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct mod_sub_list_ctx visit_ctx;
struct bt_mesh_model *mod;
struct bt_mesh_elem *elem;
u16_t addr, id;
int i;
addr = net_buf_simple_pull_le16(buf);
if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
@ -1727,11 +1728,10 @@ static void mod_sub_get(struct bt_mesh_model *model,
net_buf_simple_add_le16(msg, addr);
net_buf_simple_add_le16(msg, id);
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
net_buf_simple_add_le16(msg, mod->groups[i]);
}
}
visit_ctx.msg = msg;
visit_ctx.elem_idx = mod->elem_idx;
bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor,
&visit_ctx);
send_list:
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
@ -1747,13 +1747,10 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg =
NET_BUF_SIMPLE(2 + 7 + 4 +
MYNEWT_VAL(BLE_MESH_MODEL_GROUP_COUNT) * 2);
struct os_mbuf *msg = NET_BUF_SIMPLE(BT_MESH_TX_SDU_MAX);
struct bt_mesh_model *mod;
struct bt_mesh_elem *elem;
u16_t company, addr, id;
int i;
addr = net_buf_simple_pull_le16(buf);
if (!BT_MESH_ADDR_IS_UNICAST(addr)) {
@ -1792,11 +1789,8 @@ static void mod_sub_get_vnd(struct bt_mesh_model *model,
net_buf_simple_add_le16(msg, company);
net_buf_simple_add_le16(msg, id);
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
net_buf_simple_add_le16(msg, mod->groups[i]);
}
}
bt_mesh_model_tree_walk(bt_mesh_model_root(mod), mod_sub_list_visitor,
msg);
send_list:
if (bt_mesh_model_send(model, ctx, msg, NULL, NULL)) {
@ -1818,9 +1812,9 @@ static void mod_sub_va_add(struct bt_mesh_model *model,
struct bt_mesh_elem *elem;
u8_t *label_uuid;
u8_t *mod_id;
u16_t *entry;
u8_t status;
bool vnd;
int i;
elem_addr = net_buf_simple_pull_le16(buf);
if (!BT_MESH_ADDR_IS_UNICAST(elem_addr)) {
@ -1854,33 +1848,31 @@ static void mod_sub_va_add(struct bt_mesh_model *model,
goto send_status;
}
if (bt_mesh_model_find_group(mod, sub_addr)) {
if (bt_mesh_model_find_group(&mod, sub_addr)) {
/* Tried to add existing subscription */
status = STATUS_SUCCESS;
goto send_status;
}
for (i = 0; i < ARRAY_SIZE(mod->groups); i++) {
if (mod->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
mod->groups[i] = sub_addr;
break;
}
}
if (i == ARRAY_SIZE(mod->groups)) {
entry = bt_mesh_model_find_group(&mod, BT_MESH_ADDR_UNASSIGNED);
if (!entry) {
status = STATUS_INSUFF_RESOURCES;
} else {
if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
bt_mesh_lpn_group_add(sub_addr);
goto send_status;
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
*entry = sub_addr;
status = STATUS_SUCCESS;
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
bt_mesh_lpn_group_add(sub_addr);
}
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
}
status = STATUS_SUCCESS;
send_status:
send_mod_sub_status(model, ctx, status, elem_addr, sub_addr,
mod_id, vnd);
@ -1936,7 +1928,7 @@ static void mod_sub_va_del(struct bt_mesh_model *model,
bt_mesh_lpn_group_del(&sub_addr, 1);
}
match = bt_mesh_model_find_group(mod, sub_addr);
match = bt_mesh_model_find_group(&mod, sub_addr);
if (match) {
*match = BT_MESH_ADDR_UNASSIGNED;
@ -1992,13 +1984,10 @@ static void mod_sub_va_overwrite(struct bt_mesh_model *model,
goto send_status;
}
if ((MYNEWT_VAL(BLE_MESH_LOW_POWER))) {
bt_mesh_lpn_group_del(mod->groups, ARRAY_SIZE(mod->groups));
}
mod_sub_list_clear(mod);
if (ARRAY_SIZE(mod->groups) > 0) {
bt_mesh_model_tree_walk(bt_mesh_model_root(mod),
mod_sub_clear_visitor, NULL);
status = va_add(label_uuid, &sub_addr);
if (status == STATUS_SUCCESS) {
mod->groups[0] = sub_addr;
@ -2145,8 +2134,7 @@ static void send_net_key_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
u16_t idx, u8_t status)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NET_KEY_STATUS, 3);
bt_mesh_model_msg_init(msg, OP_NET_KEY_STATUS);
@ -2361,8 +2349,8 @@ static void net_key_get(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct os_mbuf *msg =
NET_BUF_SIMPLE(2 + 4 +
IDX_LEN(MYNEWT_VAL(BLE_MESH_SUBNET_COUNT)));
BT_MESH_MODEL_BUF(OP_NET_KEY_LIST,
IDX_LEN(CONFIG_BT_MESH_SUBNET_COUNT));
u16_t prev, i;
bt_mesh_model_msg_init(msg, OP_NET_KEY_LIST);
@ -2399,8 +2387,7 @@ static void node_identity_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_STATUS, 4);
struct bt_mesh_subnet *sub;
u8_t node_id;
u16_t idx;
@ -2441,8 +2428,7 @@ static void node_identity_set(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_IDENTITY_STATUS, 4);
struct bt_mesh_subnet *sub;
u8_t node_id;
u16_t idx;
@ -2474,12 +2460,7 @@ static void node_identity_set(struct bt_mesh_model *model,
net_buf_simple_add_u8(msg, STATUS_SUCCESS);
net_buf_simple_add_le16(msg, idx);
/* Section 4.2.11.1: "When the GATT Proxy state is set to
* 0x00, the Node Identity state for all subnets shall be set
* to 0x00 and shall not be changed."
*/
if (MYNEWT_VAL(BLE_MESH_GATT_PROXY) &&
bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) {
if (MYNEWT_VAL(BLE_MESH_GATT_PROXY)) {
if (node_id) {
bt_mesh_proxy_identity_start(sub);
} else {
@ -2522,7 +2503,7 @@ static void mod_app_bind(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_STATUS, 9);
u16_t elem_addr, key_app_idx;
struct bt_mesh_model *mod;
struct bt_mesh_elem *elem;
@ -2583,7 +2564,7 @@ static void mod_app_unbind(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_MOD_APP_STATUS, 9);
u16_t elem_addr, key_app_idx;
struct bt_mesh_model *mod;
struct bt_mesh_elem *elem;
@ -2638,7 +2619,11 @@ static void mod_app_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + KEY_LIST_LEN + 4);
struct os_mbuf *msg = NET_BUF_SIMPLE(max(BT_MESH_MODEL_BUF_LEN(OP_VND_MOD_APP_LIST,
9 + KEY_LIST_LEN),
BT_MESH_MODEL_BUF_LEN(OP_SIG_MOD_APP_LIST,
9 + KEY_LIST_LEN)));
struct bt_mesh_model *mod;
struct bt_mesh_elem *elem;
u8_t *mod_id, status;
@ -2709,8 +2694,7 @@ static void node_reset(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_NODE_RESET_STATUS, 0);
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,
@ -2733,8 +2717,7 @@ static void node_reset(struct bt_mesh_model *model,
static void send_friend_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_FRIEND_STATUS, 1);
struct bt_mesh_cfg_srv *cfg = model->user_data;
bt_mesh_model_msg_init(msg, OP_FRIEND_STATUS);
@ -2762,7 +2745,6 @@ static void friend_set(struct bt_mesh_model *model,
struct os_mbuf *buf)
{
struct bt_mesh_cfg_srv *cfg = model->user_data;
struct bt_mesh_subnet *sub;
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,
@ -2796,9 +2778,8 @@ static void friend_set(struct bt_mesh_model *model,
}
}
sub = bt_mesh_subnet_get(cfg->hb_pub.net_idx);
if ((cfg->hb_pub.feat & BT_MESH_FEAT_FRIEND) && sub) {
hb_send(model);
if (cfg->hb_pub.feat & BT_MESH_FEAT_FRIEND) {
bt_mesh_heartbeat_send();
}
send_status:
@ -2809,8 +2790,7 @@ static void lpn_timeout_get(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 5 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_LPN_TIMEOUT_STATUS, 5);
struct bt_mesh_friend *frnd;
u16_t lpn_addr;
s32_t timeout;
@ -2859,8 +2839,7 @@ static void send_krp_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
u16_t idx, u8_t phase, u8_t status)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 4 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_KRP_STATUS, 4);
bt_mesh_model_msg_init(msg, OP_KRP_STATUS);
@ -2999,8 +2978,7 @@ static void hb_pub_send_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, u8_t status,
struct hb_pub_param *orig_msg)
{
/* Needed size: opcode (1 byte) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(1 + 10 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_PUB_STATUS, 10);
struct bt_mesh_cfg_srv *cfg = model->user_data;
BT_DBG("src 0x%04x status 0x%02x", ctx->addr, status);
@ -3125,8 +3103,7 @@ failed:
static void hb_sub_send_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx, u8_t status)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 9 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEARTBEAT_SUB_STATUS, 9);
struct bt_mesh_cfg_srv *cfg = model->user_data;
u16_t period;
s64_t uptime;
@ -3306,7 +3283,6 @@ const struct bt_mesh_model_op bt_mesh_cfg_srv_op[] = {
static void hb_publish(struct ble_npl_event *work)
{
struct bt_mesh_cfg_srv *cfg = ble_npl_event_get_arg(work);
struct bt_mesh_model *model = cfg->model;
struct bt_mesh_subnet *sub;
u16_t period_ms;
@ -3329,7 +3305,7 @@ static void hb_publish(struct ble_npl_event *work)
k_delayed_work_submit(&cfg->hb_pub.timer, period_ms);
}
hb_send(model);
bt_mesh_heartbeat_send();
if (cfg->hb_pub.count != 0xffff) {
cfg->hb_pub.count--;
@ -3353,10 +3329,17 @@ static bool conf_is_valid(struct bt_mesh_cfg_srv *cfg)
return true;
}
int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary)
static int cfg_srv_init(struct bt_mesh_model *model)
{
struct bt_mesh_cfg_srv *cfg = model->user_data;
BT_DBG("");
if (!bt_mesh_model_in_primary(model)) {
BT_ERR("Configuration Server only allowed in primary element");
return -EINVAL;
}
if (!cfg) {
BT_ERR("No Configuration Server context provided");
return -EINVAL;
@ -3367,8 +3350,11 @@ int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary)
return -EINVAL;
}
/* Configuration Model security is device-key based */
model->keys[0] = BT_MESH_KEY_DEV;
/*
* Configuration Model security is device-key based and only the local
* device-key is allowed to access this model.
*/
model->keys[0] = BT_MESH_KEY_DEV_LOCAL;
if (!(MYNEWT_VAL(BLE_MESH_RELAY))) {
cfg->relay = BT_MESH_RELAY_NOT_SUPPORTED;
@ -3394,19 +3380,33 @@ int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary)
return 0;
}
const struct bt_mesh_model_cb bt_mesh_cfg_srv_cb = {
.init = cfg_srv_init,
};
static void mod_reset(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
bool vnd, bool primary, void *user_data)
{
size_t clear_count;
/* Clear model state that isn't otherwise cleared. E.g. AppKey
* binding and model publication is cleared as a consequence
* of removing all app keys, however model subscription clearing
* must be taken care of here.
* of removing all app keys, however model subscription and user data
* clearing must be taken care of here.
*/
mod_sub_list_clear(mod);
clear_count = mod_sub_list_clear(mod);
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_mod_sub(mod);
if (clear_count) {
bt_mesh_store_mod_sub(mod);
}
bt_mesh_model_data_store(mod, vnd, NULL, 0);
}
if (mod->cb && mod->cb->reset) {
mod->cb->reset(mod);
}
}
@ -3415,6 +3415,8 @@ void bt_mesh_cfg_reset(void)
struct bt_mesh_cfg_srv *cfg = conf;
int i;
BT_DBG("");
if (!cfg) {
return;
}

View File

@ -6,6 +6,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_CRYPTO_LOG
#include <string.h>
#include <stdbool.h>
#include <errno.h>
@ -26,12 +29,8 @@
#include <tinycrypt/aes.h>
#include <tinycrypt/cmac_mode.h>
#include <tinycrypt/ccm_mode.h>
#endif
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_CRYPTO))
#include "host/ble_hs_log.h"
#include "crypto.h"
#define NET_MIC_LEN(pdu) (((pdu)[1] & 0x80) ? 8 : 4)
@ -315,7 +314,7 @@ static int bt_mesh_ccm_decrypt(const u8_t key[16], u8_t nonce[13],
}
}
for (i = 0; i < aad_len; i++, j++) {
for (; i < aad_len; i++, j++) {
pmsg[i] = Xn[i] ^ aad[j];
}
@ -479,7 +478,7 @@ static int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13],
}
}
for (i = 0; i < aad_len; i++, j++) {
for (; i < aad_len; i++, j++) {
pmsg[i] = Xn[i] ^ aad[j];
}
@ -569,7 +568,6 @@ static int bt_mesh_ccm_encrypt(const u8_t key[16], u8_t nonce[13],
return 0;
}
#if (MYNEWT_VAL(BLE_MESH_PROXY))
static void create_proxy_nonce(u8_t nonce[13], const u8_t *pdu,
u32_t iv_index)
{
@ -595,7 +593,6 @@ static void create_proxy_nonce(u8_t nonce[13], const u8_t *pdu,
/* IV Index */
sys_put_be32(iv_index, &nonce[9]);
}
#endif /* PROXY */
static void create_net_nonce(u8_t nonce[13], const u8_t *pdu,
u32_t iv_index)
@ -661,15 +658,11 @@ int bt_mesh_net_encrypt(const u8_t key[16], struct os_mbuf *buf,
bt_hex(key, 16), mic_len);
BT_DBG("PDU (len %u) %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
#if (MYNEWT_VAL(BLE_MESH_PROXY))
if (proxy) {
if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && proxy) {
create_proxy_nonce(nonce, buf->om_data, iv_index);
} else {
create_net_nonce(nonce, buf->om_data, iv_index);
}
#else
create_net_nonce(nonce, buf->om_data, iv_index);
#endif
BT_DBG("Nonce %s", bt_hex(nonce, 13));
@ -692,15 +685,11 @@ int bt_mesh_net_decrypt(const u8_t key[16], struct os_mbuf *buf,
BT_DBG("iv_index %u, key %s mic_len %u", (unsigned) iv_index,
bt_hex(key, 16), mic_len);
#if (MYNEWT_VAL(BLE_MESH_PROXY))
if (proxy) {
if (IS_ENABLED(CONFIG_BT_MESH_PROXY) && proxy) {
create_proxy_nonce(nonce, buf->om_data, iv_index);
} else {
create_net_nonce(nonce, buf->om_data, iv_index);
}
#else
create_net_nonce(nonce, buf->om_data, iv_index);
#endif
BT_DBG("Nonce %s", bt_hex(nonce, 13));
@ -728,12 +717,11 @@ static void create_app_nonce(u8_t nonce[13], bool dev_key, u8_t aszmic,
sys_put_be32(iv_index, &nonce[9]);
}
int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
struct os_mbuf *buf, const u8_t *ad,
u16_t src, u16_t dst, u32_t seq_num, u32_t iv_index)
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)
{
u8_t nonce[13];
int err;
BT_DBG("AppKey %s", bt_hex(key, 16));
BT_DBG("dev_key %u src 0x%04x dst 0x%04x", dev_key, src, dst);
@ -745,8 +733,35 @@ int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
BT_DBG("Nonce %s", bt_hex(nonce, 13));
err = bt_mesh_ccm_encrypt(key, nonce, buf->om_data, buf->om_len, ad,
ad ? 16 : 0, buf->om_data, APP_MIC_LEN(aszmic));
return bt_mesh_ccm_encrypt(key, nonce, buf->om_data, buf->om_len, ad,
ad ? 16 : 0, buf->om_data,
APP_MIC_LEN(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) {
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 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));
@ -755,23 +770,43 @@ int bt_mesh_app_encrypt(const u8_t key[16], bool dev_key, u8_t aszmic,
return err;
}
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)
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];
int err;
BT_DBG("EncData (len %u) %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
BT_DBG("EncData (len %u) %s", buf->om_len,
bt_hex(buf->om_data, buf->om_len));
create_app_nonce(nonce, dev_key, aszmic, src, dst, seq_num, iv_index);
BT_DBG("AppKey %s", bt_hex(key, 16));
BT_DBG("Nonce %s", bt_hex(nonce, 13));
err = bt_mesh_ccm_decrypt(key, nonce, buf->om_data, buf->om_len, ad,
ad ? 16 : 0, out->om_data, APP_MIC_LEN(aszmic));
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);
if (!err) {
net_buf_simple_add(out, buf->om_len);
}
@ -900,6 +935,12 @@ int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13],
return bt_mesh_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])
{
return bt_mesh_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])

View File

@ -131,10 +131,18 @@ int bt_mesh_net_encrypt(const u8_t key[16], struct os_mbuf *buf,
int bt_mesh_net_decrypt(const u8_t key[16], struct os_mbuf *buf,
u32_t iv_index, bool proxy);
int bt_mesh_app_encrypt_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_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_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 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,
@ -157,4 +165,6 @@ int bt_mesh_prov_conf(const u8_t conf_key[16], const u8_t rand[16],
int bt_mesh_prov_decrypt(const u8_t key[16], u8_t nonce[13],
const u8_t data[25 + 8], u8_t out[25]);
int bt_mesh_prov_encrypt(const u8_t key[16], u8_t nonce[13],
const u8_t data[25], u8_t out[25 + 8]);
#endif

View File

@ -115,11 +115,16 @@
#define STATUS_UNSPECIFIED 0x10
#define STATUS_INVALID_BINDING 0x11
int bt_mesh_cfg_srv_init(struct bt_mesh_model *model, bool primary);
int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary);
enum {
BT_MESH_VA_CHANGED, /* Label information changed */
};
int bt_mesh_cfg_cli_init(struct bt_mesh_model *model, bool primary);
int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary);
struct label {
u16_t ref;
u16_t addr;
u8_t uuid[16];
atomic_t flags[1];
};
void bt_mesh_cfg_reset(void);
@ -127,6 +132,8 @@ 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);

View File

@ -1,4 +1,4 @@
/* Bluetooth Mesh */
/* Bluetooth Mesh */
/*
* Copyright (c) 2017 Intel Corporation
@ -6,17 +6,15 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_CRYPTO_LOG
#if MYNEWT_VAL(BLE_MESH_FRIEND)
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_FRIEND))
#include "host/ble_hs_log.h"
#include "mesh/mesh.h"
#include "mesh/slist.h"
#include "mesh_priv.h"
@ -40,9 +38,9 @@ static os_membuf_t friend_buf_mem[OS_MEMPOOL_SIZE(
struct os_mbuf_pool friend_os_mbuf_pool;
static struct os_mempool friend_buf_mempool;
#define NET_BUF_FRAGS BIT(0)
#define FRIEND_ADV(buf) CONTAINER_OF(BT_MESH_ADV(buf), \
struct friend_adv, adv)
#define FRIEND_ADV(buf) CONTAINER_OF(BT_MESH_ADV(buf), struct friend_adv, adv)
/* PDUs from Friend to the LPN should only be transmitted once with the
* smallest possible interval (20ms).
@ -63,54 +61,15 @@ struct friend_pdu_info {
static struct friend_adv {
struct bt_mesh_adv adv;
u64_t seq_auth;
u16_t app_idx;
} adv_pool[FRIEND_BUF_COUNT];
static struct bt_mesh_adv *adv_alloc(int id)
{
adv_pool[id].app_idx = BT_MESH_KEY_UNUSED;
return &adv_pool[id].adv;
}
static void discard_buffer(void)
{
struct bt_mesh_friend *frnd = &bt_mesh.frnd[0];
struct os_mbuf *buf;
int i;
/* Find the Friend context with the most queued buffers */
for (i = 1; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
if (bt_mesh.frnd[i].queue_size > frnd->queue_size) {
frnd = &bt_mesh.frnd[i];
}
}
buf = net_buf_slist_get(&frnd->queue);
__ASSERT_NO_MSG(buf != NULL);
BT_WARN("Discarding buffer %p for LPN 0x%04x", buf, frnd->lpn);
net_buf_unref(buf);
}
static struct os_mbuf *friend_buf_alloc(u16_t src)
{
struct os_mbuf *buf;
do {
buf = bt_mesh_adv_create_from_pool(&friend_os_mbuf_pool, adv_alloc,
BT_MESH_ADV_DATA,
FRIEND_XMIT, K_NO_WAIT);
if (!buf) {
discard_buffer();
}
} while (!buf);
BT_MESH_ADV(buf)->addr = src;
FRIEND_ADV(buf)->seq_auth = TRANS_SEQ_AUTH_NVAL;
BT_DBG("allocated buf %p", buf);
return buf;
}
static bool is_lpn_unicast(struct bt_mesh_friend *frnd, u16_t addr)
{
if (frnd->lpn == BT_MESH_ADDR_UNASSIGNED) {
@ -150,6 +109,17 @@ struct bt_mesh_friend *bt_mesh_friend_find(u16_t net_idx, u16_t lpn_addr,
return NULL;
}
static void purge_buffers(struct net_buf_slist_t *list)
{
struct os_mbuf *buf;
while (!net_buf_slist_is_empty(list)) {
buf = (void *)net_buf_slist_get(list);
BT_MESH_ADV(buf)->flags &= ~NET_BUF_FRAGS;
net_buf_unref(buf);
}
}
/* Intentionally start a little bit late into the ReceiveWindow when
* it's large enough. This may improve reliability with some platforms,
* like the PTS, where the receiver might not have sufficiently compensated
@ -184,16 +154,13 @@ static void friend_clear(struct bt_mesh_friend *frnd)
frnd->last = NULL;
}
while (!net_buf_slist_is_empty(&frnd->queue)) {
net_buf_unref(net_buf_slist_get(&frnd->queue));
}
purge_buffers(&frnd->queue);
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
while (!net_buf_slist_is_empty(&seg->queue)) {
net_buf_unref(net_buf_slist_get(&seg->queue));
}
purge_buffers(&seg->queue);
seg->seg_count = 0U;
}
frnd->valid = 0;
@ -327,29 +294,16 @@ static struct os_mbuf *create_friend_pdu(struct bt_mesh_friend *frnd,
struct friend_pdu_info *info,
struct os_mbuf *sdu)
{
struct bt_mesh_subnet *sub;
const u8_t *enc, *priv;
struct os_mbuf *buf;
u8_t nid;
sub = bt_mesh_subnet_get(frnd->net_idx);
__ASSERT_NO_MSG(sub != NULL);
buf = friend_buf_alloc(info->src);
/* Friend Offer needs master security credentials */
if (info->ctl && TRANS_CTL_OP(sdu->om_data) == TRANS_CTL_OP_FRIEND_OFFER) {
enc = sub->keys[sub->kr_flag].enc;
priv = sub->keys[sub->kr_flag].privacy;
nid = sub->keys[sub->kr_flag].nid;
} else {
if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) {
BT_ERR("friend_cred_get failed");
goto failed;
}
buf = bt_mesh_adv_create_from_pool(&friend_os_mbuf_pool, adv_alloc,
BT_MESH_ADV_DATA,
FRIEND_XMIT, K_NO_WAIT);
if (!buf) {
return NULL;
}
net_buf_add_u8(buf, (nid | (info->iv_index & 1) << 7));
net_buf_add_u8(buf, (info->iv_index & 1) << 7); /* Will be reset in encryption */
if (info->ctl) {
net_buf_add_u8(buf, info->ttl | 0x80);
@ -364,25 +318,187 @@ static struct os_mbuf *create_friend_pdu(struct bt_mesh_friend *frnd,
net_buf_add_mem(buf, sdu->om_data, sdu->om_len);
/* We re-encrypt and obfuscate using the received IVI rather than
* the normal TX IVI (which may be different) since the transport
* layer nonce includes the IVI.
*/
if (bt_mesh_net_encrypt(enc, buf, info->iv_index, false)) {
BT_ERR("Re-encrypting failed");
goto failed;
}
if (bt_mesh_net_obfuscate(buf->om_data, info->iv_index, priv)) {
BT_ERR("Re-obfuscating failed");
goto failed;
}
return buf;
}
failed:
net_buf_unref(buf);
return NULL;
struct unseg_app_sdu_meta {
struct bt_mesh_net_rx net;
const u8_t *key;
struct bt_mesh_subnet *subnet;
bool is_dev_key;
u8_t aid;
u8_t *ad;
};
static int unseg_app_sdu_unpack(struct bt_mesh_friend *frnd,
struct os_mbuf *buf,
struct unseg_app_sdu_meta *meta)
{
u16_t app_idx = FRIEND_ADV(buf)->app_idx;
int err;
meta->subnet = bt_mesh_subnet_get(frnd->net_idx);
meta->is_dev_key = (app_idx == BT_MESH_KEY_DEV);
meta->is_dev_key = BT_MESH_IS_DEV_KEY(app_idx);
bt_mesh_net_header_parse(buf, &meta->net);
err = bt_mesh_app_key_get(meta->subnet, app_idx, meta->net.ctx.recv_dst,
&meta->key, &meta->aid);
if (err) {
return err;
}
if (BT_MESH_ADDR_IS_VIRTUAL(meta->net.ctx.recv_dst)) {
meta->ad = bt_mesh_label_uuid_get(meta->net.ctx.recv_dst);
if (!meta->ad) {
return -ENOENT;
}
} else {
meta->ad = NULL;
}
return 0;
}
static int unseg_app_sdu_decrypt(struct bt_mesh_friend *frnd,
struct os_mbuf *buf,
const struct unseg_app_sdu_meta *meta)
{
struct net_buf_simple_state state;
int err;
BT_DBG("");
net_buf_simple_save(buf, &state);
net_buf_simple_pull_mem(buf, 10);
buf->om_len -= 4;
err = bt_mesh_app_decrypt_in_place(meta->key, meta->is_dev_key,
0, buf, meta->ad, meta->net.ctx.addr,
meta->net.ctx.recv_dst, meta->net.seq,
BT_MESH_NET_IVI_TX);
net_buf_simple_restore(buf, &state);
return err;
}
static int unseg_app_sdu_encrypt(struct bt_mesh_friend *frnd,
struct os_mbuf *buf,
const struct unseg_app_sdu_meta *meta)
{
struct net_buf_simple_state state;
int err;
BT_DBG("");
net_buf_simple_save(buf, &state);
net_buf_simple_pull_mem(buf, 10);
buf->om_len -= 4;
err = bt_mesh_app_encrypt_in_place(meta->key, meta->is_dev_key, 0, buf,
meta->ad, meta->net.ctx.addr,
meta->net.ctx.recv_dst, bt_mesh.seq,
BT_MESH_NET_IVI_TX);
net_buf_simple_restore(buf, &state);
return err;
}
static int unseg_app_sdu_prepare(struct bt_mesh_friend *frnd,
struct os_mbuf *buf)
{
struct unseg_app_sdu_meta meta;
int err;
BT_DBG("");
if (FRIEND_ADV(buf)->app_idx == BT_MESH_KEY_UNUSED) {
return 0;
}
err = unseg_app_sdu_unpack(frnd, buf, &meta);
if (err) {
return err;
}
/* No need to reencrypt the message if the sequence number is
* unchanged.
*/
if (meta.net.seq == bt_mesh.seq) {
return 0;
}
err = unseg_app_sdu_decrypt(frnd, buf, &meta);
if (err) {
BT_WARN("Decryption failed! %d", err);
return err;
}
err = unseg_app_sdu_encrypt(frnd, buf, &meta);
if (err) {
BT_WARN("Re-encryption failed! %d", err);
}
return err;
}
static int encrypt_friend_pdu(struct bt_mesh_friend *frnd, struct os_mbuf *buf,
bool master_cred)
{
struct bt_mesh_subnet *sub = bt_mesh_subnet_get(frnd->net_idx);
const u8_t *enc, *priv;
u32_t iv_index;
u16_t src;
u8_t nid;
int err;
if (master_cred) {
enc = sub->keys[sub->kr_flag].enc;
priv = sub->keys[sub->kr_flag].privacy;
nid = sub->keys[sub->kr_flag].nid;
} else {
if (friend_cred_get(sub, frnd->lpn, &nid, &enc, &priv)) {
BT_ERR("friend_cred_get failed");
return -ENOENT;
}
}
src = sys_get_be16(&buf->om_data[5]);
if (bt_mesh_elem_find(src)) {
u32_t seq;
if (FRIEND_ADV(buf)->app_idx != BT_MESH_KEY_UNUSED) {
err = unseg_app_sdu_prepare(frnd, buf);
if (err) {
return err;
}
}
seq = bt_mesh_next_seq();
buf->om_data[2] = seq >> 16;
buf->om_data[3] = seq >> 8;
buf->om_data[4] = seq;
iv_index = BT_MESH_NET_IVI_TX;
FRIEND_ADV(buf)->app_idx = BT_MESH_KEY_UNUSED;
} else {
u8_t ivi = (buf->om_data[0] >> 7);
iv_index = (bt_mesh.iv_index - ((bt_mesh.iv_index & 1) != ivi));
}
buf->om_data[0] = (nid | (iv_index & 1) << 7);
if (bt_mesh_net_encrypt(enc, buf, iv_index, false)) {
BT_ERR("Encrypting failed");
return -EINVAL;
}
if (bt_mesh_net_obfuscate(buf->om_data, iv_index, priv)) {
BT_ERR("Obfuscating failed");
return -EINVAL;
}
return 0;
}
static struct os_mbuf *encode_friend_ctl(struct bt_mesh_friend *frnd,
@ -390,7 +506,6 @@ static struct os_mbuf *encode_friend_ctl(struct bt_mesh_friend *frnd,
struct os_mbuf *sdu)
{
struct friend_pdu_info info;
u32_t seq;
BT_DBG("LPN 0x%04x", frnd->lpn);
@ -402,10 +517,7 @@ static struct os_mbuf *encode_friend_ctl(struct bt_mesh_friend *frnd,
info.ctl = 1;
info.ttl = 0;
seq = bt_mesh_next_seq();
info.seq[0] = seq >> 16;
info.seq[1] = seq >> 8;
info.seq[2] = seq;
memset(info.seq, 0, sizeof(info.seq));
info.iv_index = BT_MESH_NET_IVI_TX;
@ -455,6 +567,10 @@ static void enqueue_sub_cfm(struct bt_mesh_friend *frnd, u8_t xact)
goto done;
}
if (encrypt_friend_pdu(frnd, buf, false)) {
return;
}
if (frnd->last) {
BT_DBG("Discarding last PDU");
net_buf_unref(frnd->last);
@ -693,8 +809,8 @@ static void clear_procedure_start(struct bt_mesh_friend *frnd)
{
BT_DBG("LPN 0x%04x (old) Friend 0x%04x", frnd->lpn, frnd->clear.frnd);
frnd->clear.start = k_uptime_get_32() + (2 * frnd->poll_to);
frnd->clear.repeat_sec = 1;
frnd->clear.start = k_uptime_get_32();
frnd->clear.repeat_sec = 1U;
send_friend_clear(frnd);
}
@ -763,6 +879,10 @@ static void enqueue_offer(struct bt_mesh_friend *frnd, s8_t rssi)
goto done;
}
if (encrypt_friend_pdu(frnd, buf, true)) {
return;
}
frnd->counter++;
if (frnd->last) {
@ -886,7 +1006,7 @@ init_friend:
frnd->clear.frnd = sys_be16_to_cpu(msg->prev_addr);
BT_DBG("LPN 0x%04x rssi %d recv_delay %u poll_to %ums",
frnd->lpn, rx->rssi, frnd->recv_delay,
frnd->lpn, rx->ctx.recv_rssi, frnd->recv_delay,
(unsigned) frnd->poll_to);
if (BT_MESH_ADDR_IS_UNICAST(frnd->clear.frnd) &&
@ -895,45 +1015,70 @@ init_friend:
}
k_delayed_work_submit(&frnd->timer,
offer_delay(frnd, rx->rssi, msg->criteria));
offer_delay(frnd, rx->ctx.recv_rssi,
msg->criteria));
friend_cred_create(rx->sub, frnd->lpn, frnd->lpn_counter,
frnd->counter);
enqueue_offer(frnd, rx->rssi);
enqueue_offer(frnd, rx->ctx.recv_rssi);
return 0;
}
static bool is_seg(struct bt_mesh_friend_seg *seg, u16_t src, u16_t seq_zero)
{
struct os_mbuf *buf = (void *)net_buf_slist_peek_head(&seg->queue);
struct net_buf_simple_state state;
u16_t buf_seq_zero;
u16_t buf_src;
if (!buf) {
return false;
}
net_buf_simple_save(buf, &state);
net_buf_skip(buf, 5); /* skip IVI, NID, CTL, TTL, SEQ */
buf_src = net_buf_pull_be16(buf);
net_buf_skip(buf, 3); /* skip DST, OP/AID */
buf_seq_zero = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK);
net_buf_simple_restore(buf, &state);
return ((src == buf_src) && (seq_zero == buf_seq_zero));
}
static struct bt_mesh_friend_seg *get_seg(struct bt_mesh_friend *frnd,
u16_t src, u64_t *seq_auth)
u16_t src, u16_t seq_zero,
u8_t seg_count)
{
struct bt_mesh_friend_seg *unassigned = NULL;
int i;
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
struct os_mbuf *buf = (void *)net_buf_slist_peek_head(&seg->queue);
if (buf && BT_MESH_ADV(buf)->addr == src &&
FRIEND_ADV(buf)->seq_auth == *seq_auth) {
if (is_seg(seg, src, seq_zero)) {
return seg;
}
if (!unassigned && !buf) {
if (!unassigned && !net_buf_slist_peek_head(&seg->queue)) {
unassigned = seg;
}
}
if (unassigned) {
unassigned->seg_count = seg_count;
}
return unassigned;
}
static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
enum bt_mesh_friend_pdu_type type,
u16_t src, u8_t seg_count,
struct os_mbuf *buf)
{
struct bt_mesh_friend_seg *seg;
struct friend_adv *adv;
BT_DBG("type %u", type);
@ -946,11 +1091,11 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
return;
}
adv = FRIEND_ADV(buf);
seg = get_seg(frnd, BT_MESH_ADV(buf)->addr, &adv->seq_auth);
u16_t seq_zero = (((buf->om_data[10] << 8 | buf->om_data[11]) >> 2) & TRANS_SEQ_ZERO_MASK);
seg = get_seg(frnd, src, seq_zero, seg_count);
if (!seg) {
BT_ERR("No free friend segment RX contexts for 0x%04x",
BT_MESH_ADV(buf)->addr);
BT_ERR("No free friend segment RX contexts for 0x%04x", src);
net_buf_unref(buf);
return;
}
@ -962,19 +1107,13 @@ static void enqueue_friend_pdu(struct bt_mesh_friend *frnd,
enqueue_update(frnd, 1);
}
/* Only acks should have a valid SeqAuth in the Friend queue
* (otherwise we can't easily detect them there), so clear
* the SeqAuth information from the segments before merging.
*/
struct os_mbuf *m;
struct os_mbuf_pkthdr *pkthdr;
NET_BUF_SLIST_FOR_EACH_NODE(&seg->queue, pkthdr) {
m = OS_MBUF_PKTHDR_TO_MBUF(pkthdr);
FRIEND_ADV(m)->seq_auth = TRANS_SEQ_AUTH_NVAL;
frnd->queue_size++;
}
net_buf_slist_merge_slist(&frnd->queue, &seg->queue);
frnd->queue_size += seg->seg_count;
seg->seg_count = 0U;
} else {
/* Mark the buffer as having more to come after it */
BT_MESH_ADV(buf)->flags |= NET_BUF_FRAGS;
}
}
@ -1040,13 +1179,21 @@ static void friend_timeout(struct ble_npl_event *work)
return;
}
frnd->last = net_buf_slist_get(&frnd->queue);
frnd->last = (void *)net_buf_slist_get(&frnd->queue);
if (!frnd->last) {
BT_WARN("Friendship not established with 0x%04x", frnd->lpn);
BT_WARN("Friendship not established with 0x%04x",
frnd->lpn);
friend_clear(frnd);
return;
}
if (encrypt_friend_pdu(frnd, frnd->last, false)) {
return;
}
/* Clear the flag we use for segment tracking */
BT_MESH_ADV(frnd->last)->flags &= ~NET_BUF_FRAGS;
BT_DBG("Sending buf %p from Friend Queue of LPN 0x%04x",
frnd->last, frnd->lpn);
frnd->queue_size--;
@ -1093,6 +1240,42 @@ int bt_mesh_friend_init(void)
return 0;
}
static bool is_segack(struct os_mbuf *buf, u64_t *seqauth, u16_t src)
{
struct net_buf_simple_state state;
bool found = false;
if (buf->om_len != 16) {
return false;
}
net_buf_simple_save(buf, &state);
net_buf_skip(buf, 1); /* skip IVI, NID */
if (!(net_buf_pull_u8(buf) >> 7)) {
goto end;
}
net_buf_pull(buf, 3); /* skip SEQNUM */
if (src != net_buf_pull_be16(buf)) {
goto end;
}
net_buf_skip(buf, 2); /* skip dst */
if (TRANS_CTL_OP((u8_t *) net_buf_pull_mem(buf, 1)) != TRANS_CTL_OP_ACK) {
goto end;
}
found = ((net_buf_pull_be16(buf) >> 2) & TRANS_SEQ_ZERO_MASK) ==
(*seqauth & TRANS_SEQ_ZERO_MASK);
end:
net_buf_simple_restore(buf, &state);
return found;
}
static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
u16_t src)
{
@ -1104,8 +1287,7 @@ static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
cur != NULL; prev = cur, cur = net_buf_slist_peek_next(cur)) {
struct os_mbuf *buf = (void *)cur;
if (BT_MESH_ADV(buf)->addr == src &&
FRIEND_ADV(buf)->seq_auth == *seq_auth) {
if (is_segack(buf, seq_auth, src)) {
BT_DBG("Removing old ack from Friend Queue");
net_buf_slist_remove(&frnd->queue, prev, cur);
@ -1120,11 +1302,20 @@ static void friend_purge_old_ack(struct bt_mesh_friend *frnd, u64_t *seq_auth,
static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd,
struct bt_mesh_net_rx *rx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, struct os_mbuf *sbuf)
u64_t *seq_auth, u8_t seg_count,
struct os_mbuf *sbuf)
{
struct friend_pdu_info info;
struct os_mbuf *buf;
/* Because of network loopback, tx packets will also be passed into
* this rx function. These packets have already been added to the
* queue, and should be ignored.
*/
if (bt_mesh_elem_find(rx->ctx.addr)) {
return;
}
BT_DBG("LPN 0x%04x queue_size %u", frnd->lpn,
(unsigned) frnd->queue_size);
@ -1155,11 +1346,7 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd,
return;
}
if (seq_auth) {
FRIEND_ADV(buf)->seq_auth = *seq_auth;
}
enqueue_friend_pdu(frnd, type, buf);
enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
BT_DBG("Queued message for LPN 0x%04x, queue_size %u",
frnd->lpn, (unsigned) frnd->queue_size);
@ -1168,11 +1355,11 @@ static void friend_lpn_enqueue_rx(struct bt_mesh_friend *frnd,
static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
struct bt_mesh_net_tx *tx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, struct os_mbuf *sbuf)
u64_t *seq_auth, u8_t seg_count,
struct os_mbuf *sbuf)
{
struct friend_pdu_info info;
struct os_mbuf *buf;
u32_t seq;
BT_DBG("LPN 0x%04x", frnd->lpn);
@ -1186,10 +1373,9 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
info.ttl = tx->ctx->send_ttl;
info.ctl = (tx->ctx->app_idx == BT_MESH_KEY_UNUSED);
seq = bt_mesh_next_seq();
info.seq[0] = seq >> 16;
info.seq[1] = seq >> 8;
info.seq[2] = seq;
info.seq[0] = (bt_mesh.seq >> 16);
info.seq[1] = (bt_mesh.seq >> 8);
info.seq[2] = bt_mesh.seq;
info.iv_index = BT_MESH_NET_IVI_TX;
@ -1199,11 +1385,15 @@ static void friend_lpn_enqueue_tx(struct bt_mesh_friend *frnd,
return;
}
if (seq_auth) {
FRIEND_ADV(buf)->seq_auth = *seq_auth;
if (type == BT_MESH_FRIEND_PDU_SINGLE && !info.ctl) {
/* Unsegmented application packets may be reencrypted later,
* as they depend on the the sequence number being the same
* when encrypting in transport and network.
*/
FRIEND_ADV(buf)->app_idx = tx->ctx->app_idx;
}
enqueue_friend_pdu(frnd, type, buf);
enqueue_friend_pdu(frnd, type, info.src, seg_count, buf);
BT_DBG("Queued message for LPN 0x%04x", frnd->lpn);
}
@ -1253,9 +1443,112 @@ bool bt_mesh_friend_match(u16_t net_idx, u16_t addr)
return false;
}
static bool friend_queue_has_space(struct bt_mesh_friend *frnd, u16_t addr,
u64_t *seq_auth, u8_t seg_count)
{
u32_t total = 0;
int i;
if (seg_count > CONFIG_BT_MESH_FRIEND_QUEUE_SIZE) {
return false;
}
for (i = 0; i < ARRAY_SIZE(frnd->seg); i++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[i];
if (seq_auth && is_seg(seg, addr, *seq_auth & TRANS_SEQ_ZERO_MASK)) {
/* If there's a segment queue for this message then the
* space verification has already happened.
*/
return true;
}
total += seg->seg_count;
}
/* If currently pending segments combined with this segmented message
* are more than the Friend Queue Size, then there's no space. This
* is because we don't have a mechanism of aborting already pending
* segmented messages to free up buffers.
*/
return (CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - total) > seg_count;
}
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 someone_has_space = false, friend_match = false;
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
if (!friend_lpn_matches(frnd, net_idx, dst)) {
continue;
}
friend_match = true;
if (friend_queue_has_space(frnd, src, seq_auth, seg_count)) {
someone_has_space = true;
}
}
/* If there were no matched LPNs treat this as success, so the
* transport layer can continue its work.
*/
if (!friend_match) {
return true;
}
/* From the transport layers perspective it's good enough that at
* least one Friend Queue has space. If there were multiple Friend
* matches then the destination must be a group address, in which
* case e.g. segment acks are not sent.
*/
return someone_has_space;
}
static bool friend_queue_prepare_space(struct bt_mesh_friend *frnd, u16_t addr,
u64_t *seq_auth, u8_t seg_count)
{
bool pending_segments;
u8_t avail_space;
if (!friend_queue_has_space(frnd, addr, seq_auth, seg_count)) {
return false;
}
avail_space = CONFIG_BT_MESH_FRIEND_QUEUE_SIZE - frnd->queue_size;
pending_segments = false;
while (pending_segments || avail_space < seg_count) {
struct os_mbuf *buf = (void *)net_buf_slist_get(&frnd->queue);
if (!buf) {
BT_ERR("Unable to free up enough buffers");
return false;
}
frnd->queue_size--;
avail_space++;
pending_segments = (BT_MESH_ADV(buf)->flags & NET_BUF_FRAGS);
BT_DBG("PENDING SEGMENTS %d", pending_segments);
/* Make sure old slist entry state doesn't remain */
BT_MESH_ADV(buf)->flags &= ~NET_BUF_FRAGS;
net_buf_unref(buf);
}
return true;
}
void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, struct os_mbuf *sbuf)
u64_t *seq_auth, u8_t seg_count,
struct os_mbuf *sbuf)
{
int i;
@ -1272,16 +1565,25 @@ void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx,
for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
if (friend_lpn_matches(frnd, rx->sub->net_idx,
rx->ctx.recv_dst)) {
friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, sbuf);
if (!friend_lpn_matches(frnd, rx->sub->net_idx,
rx->ctx.recv_dst)) {
continue;
}
if (!friend_queue_prepare_space(frnd, rx->ctx.addr, seq_auth,
seg_count)) {
continue;
}
friend_lpn_enqueue_rx(frnd, rx, type, seq_auth, seg_count,
sbuf);
}
}
bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, struct os_mbuf *sbuf)
u64_t *seq_auth, u8_t seg_count,
struct os_mbuf *sbuf)
{
bool matched = false;
int i;
@ -1297,10 +1599,19 @@ bool bt_mesh_friend_enqueue_tx(struct bt_mesh_net_tx *tx,
for (i = 0; i < ARRAY_SIZE(bt_mesh.frnd); i++) {
struct bt_mesh_friend *frnd = &bt_mesh.frnd[i];
if (friend_lpn_matches(frnd, tx->sub->net_idx, tx->ctx->addr)) {
friend_lpn_enqueue_tx(frnd, tx, type, seq_auth, sbuf);
matched = true;
if (!friend_lpn_matches(frnd, tx->sub->net_idx,
tx->ctx->addr)) {
continue;
}
if (!friend_queue_prepare_space(frnd, tx->src, seq_auth,
seg_count)) {
continue;
}
friend_lpn_enqueue_tx(frnd, tx, type, seq_auth, seg_count,
sbuf);
matched = true;
}
return matched;
@ -1323,26 +1634,16 @@ void bt_mesh_friend_clear_incomplete(struct bt_mesh_subnet *sub, u16_t src,
for (j = 0; j < ARRAY_SIZE(frnd->seg); j++) {
struct bt_mesh_friend_seg *seg = &frnd->seg[j];
struct os_mbuf *buf;
buf = (void *)net_buf_slist_peek_head(&seg->queue);
if (!buf) {
continue;
}
if (BT_MESH_ADV(buf)->addr != src) {
continue;
}
if (FRIEND_ADV(buf)->seq_auth != *seq_auth) {
if (!is_seg(seg, src, *seq_auth & TRANS_SEQ_ZERO_MASK)) {
continue;
}
BT_WARN("Clearing incomplete segments for 0x%04x", src);
while (!net_buf_slist_is_empty(&seg->queue)) {
net_buf_unref(net_buf_slist_get(&seg->queue));
}
purge_buffers(&seg->queue);
seg->seg_count = 0U;
break;
}
}
}

View File

@ -22,12 +22,17 @@ bool bt_mesh_friend_match(u16_t net_idx, u16_t addr);
struct bt_mesh_friend *bt_mesh_friend_find(u16_t net_idx, u16_t lpn_addr,
bool valid, bool established);
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);
void bt_mesh_friend_enqueue_rx(struct bt_mesh_net_rx *rx,
enum bt_mesh_friend_pdu_type type,
u64_t *seq_auth, struct os_mbuf *sbuf);
u64_t *seq_auth, u8_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, struct os_mbuf *sbuf);
u64_t *seq_auth, u8_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);

View File

@ -17,6 +17,9 @@
* under the License.
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_LOG
#include "mesh/glue.h"
#include "adv.h"
#ifndef MYNEWT
@ -27,22 +30,6 @@
#include "base64/base64.h"
#endif
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG))
#if MYNEWT_VAL(BLE_EXT_ADV)
#define BT_MESH_ADV_INST (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES))
#if MYNEWT_VAL(BLE_MESH_PROXY)
/* Note that BLE_MULTI_ADV_INSTANCES contains number of additional instances.
* Instance 0 is always there
*/
#if MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) < 1
#error "Mesh needs at least BLE_MULTI_ADV_INSTANCES set to 1"
#endif
#define BT_MESH_ADV_GATT_INST (MYNEWT_VAL(BLE_MULTI_ADV_INSTANCES) - 1)
#endif /* BLE_MESH_PROXY */
#endif /* BLE_EXT_ADV */
extern u8_t g_mesh_addr_type;
#if MYNEWT_VAL(BLE_EXT_ADV)
@ -133,13 +120,16 @@ bt_encrypt_be(const uint8_t *key, const uint8_t *plaintext, uint8_t *enc_data)
mbedtls_aes_init(&s);
if (mbedtls_aes_setkey_enc(&s, key, 128) != 0) {
mbedtls_aes_free(&s);
return BLE_HS_EUNKNOWN;
}
if (mbedtls_aes_crypt_ecb(&s, MBEDTLS_AES_ENCRYPT, plaintext, enc_data) != 0) {
mbedtls_aes_free(&s);
return BLE_HS_EUNKNOWN;
}
mbedtls_aes_free(&s);
return 0;
}
@ -872,13 +862,11 @@ void net_buf_slist_remove(struct net_buf_slist_t *list, struct os_mbuf *prev,
void net_buf_slist_merge_slist(struct net_buf_slist_t *list,
struct net_buf_slist_t *list_to_append)
{
struct os_mbuf_pkthdr *pkthdr;
STAILQ_FOREACH(pkthdr, list_to_append, omp_next) {
STAILQ_INSERT_TAIL(list, pkthdr, omp_next);
if (!STAILQ_EMPTY(list_to_append)) {
*(list)->stqh_last = list_to_append->stqh_first;
(list)->stqh_last = list_to_append->stqh_last;
STAILQ_INIT(list_to_append);
}
STAILQ_INIT(list);
}
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
@ -889,7 +877,8 @@ int settings_bytes_from_str(char *val_str, void *vp, int *len)
return 0;
}
char *settings_str_from_bytes(void *vp, int vp_len, char *buf, int buf_len)
char *settings_str_from_bytes(const void *vp, int vp_len,
char *buf, int buf_len)
{
if (BASE64_ENCODE_SIZE(vp_len) > buf_len) {
return NULL;

View File

@ -6,14 +6,13 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include "syscfg/syscfg.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_MODEL))
#include "host/ble_hs_log.h"
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "adv.h"
@ -206,7 +205,7 @@ static int cli_wait(void)
int bt_mesh_health_attention_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *attention)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
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,
@ -241,7 +240,7 @@ done:
int bt_mesh_health_attention_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t attention, u8_t *updated_attention)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
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,
@ -287,7 +286,7 @@ done:
int bt_mesh_health_period_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t *divisor)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 0 + 4);
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,
@ -322,7 +321,7 @@ done:
int bt_mesh_health_period_set(u16_t net_idx, u16_t addr, u16_t app_idx,
u8_t divisor, u8_t *updated_divisor)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
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,
@ -369,7 +368,7 @@ int bt_mesh_health_fault_test(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t test_id, u8_t *faults,
size_t *fault_count)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 3 + 4);
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,
@ -420,7 +419,7 @@ int bt_mesh_health_fault_clear(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
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,
@ -470,7 +469,7 @@ int bt_mesh_health_fault_get(u16_t net_idx, u16_t addr, u16_t app_idx,
u16_t cid, u8_t *test_id, u8_t *faults,
size_t *fault_count)
{
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 2 + 4);
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,
@ -528,11 +527,11 @@ int bt_mesh_health_cli_set(struct bt_mesh_model *model)
return 0;
}
int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary)
static int health_cli_init(struct bt_mesh_model *model)
{
struct bt_mesh_health_cli *cli = model->user_data;
BT_DBG("primary %u", primary);
BT_DBG("primary %u", bt_mesh_model_in_primary(model));
if (!cli) {
BT_ERR("No Health Client context provided");
@ -551,3 +550,7 @@ int bt_mesh_health_cli_init(struct bt_mesh_model *model, bool primary)
return 0;
}
const struct bt_mesh_model_cb bt_mesh_health_cli_cb = {
.init = health_cli_init,
};

View File

@ -6,14 +6,13 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG
#include <string.h>
#include <errno.h>
#include <stdbool.h>
#include "syscfg/syscfg.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_MODEL))
#include "host/ble_hs_log.h"
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "adv.h"
@ -218,8 +217,7 @@ done:
static void send_attention_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_ATTENTION_STATUS, 1);
struct bt_mesh_health_srv *srv = model->user_data;
u8_t time;
@ -273,8 +271,7 @@ static void attention_set(struct bt_mesh_model *model,
static void send_health_period_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
/* Needed size: opcode (2 bytes) + msg + MIC */
struct os_mbuf *msg = NET_BUF_SIMPLE(2 + 1 + 4);
struct os_mbuf *msg = BT_MESH_MODEL_BUF(OP_HEALTH_PERIOD_STATUS, 1);
bt_mesh_model_msg_init(msg, OP_HEALTH_PERIOD_STATUS);
@ -347,8 +344,10 @@ static int health_pub_update(struct bt_mesh_model *mod)
BT_DBG("");
count = health_get_current(mod, pub->msg);
if (!count) {
pub->period_div = 0;
if (count) {
pub->fast_period = 1U;
} else {
pub->fast_period = 0U;
}
return 0;
@ -363,6 +362,15 @@ int bt_mesh_fault_update(struct bt_mesh_elem *elem)
return -EINVAL;
}
/* Let periodic publishing, if enabled, take care of sending the
* Health Current Status.
*/
if (bt_mesh_model_pub_period_get(mod)) {
return 0;
}
health_pub_update(mod);
return bt_mesh_model_publish(mod);
}
@ -376,12 +384,12 @@ static void attention_off(struct ble_npl_event *work)
}
}
int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary)
static int health_srv_init(struct bt_mesh_model *model)
{
struct bt_mesh_health_srv *srv = model->user_data;
if (!srv) {
if (!primary) {
if (!bt_mesh_model_in_primary(model)) {
return 0;
}
@ -401,13 +409,17 @@ int bt_mesh_health_srv_init(struct bt_mesh_model *model, bool primary)
srv->model = model;
if (primary) {
if (bt_mesh_model_in_primary(model)) {
health_srv = srv;
}
return 0;
}
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)
{
struct bt_mesh_health_srv *srv;

View File

@ -7,14 +7,12 @@
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_LOW_POWER_LOG
#if MYNEWT_VAL(BLE_MESH_LOW_POWER)
#include <stdint.h>
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_LOW_POWER))
#include "host/ble_hs_log.h"
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "crypto.h"
@ -66,7 +64,7 @@
static void (*lpn_cb)(u16_t friend_addr, bool established);
#if MYNEWT_VAL(BLE_MESH_DEBUG_LOW_POWER)
#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
static const char *state2str(int state)
{
switch (state) {
@ -92,11 +90,11 @@ static const char *state2str(int state)
return "(unknown)";
}
}
#endif /* CONFIG_BLUETOOTH_MESH_DEBUG_LPN */
#endif
static inline void lpn_set_state(int state)
{
#if MYNEWT_VAL(BLE_MESH_DEBUG_LOW_POWER)
#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
BT_DBG("%s -> %s", state2str(bt_mesh.lpn.state), state2str(state));
#endif
bt_mesh.lpn.state = state;
@ -196,6 +194,7 @@ static int send_friend_clear(void)
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);
@ -243,6 +242,10 @@ 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();
}
if (disable) {
lpn_set_state(BT_MESH_LPN_DISABLED);
return;
@ -311,7 +314,7 @@ static void req_sent(u16_t duration, int err, void *user_data)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
#if BT_DBG_ENABLED
#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
BT_DBG("req 0x%02x duration %u err %d state %s",
lpn->sent_req, duration, err, state2str(lpn->state));
#endif
@ -725,7 +728,7 @@ static void lpn_timeout(struct ble_npl_event *work)
{
struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
#if MYNEWT_VAL(BLE_MESH_DEBUG_LOW_POWER)
#if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
BT_DBG("state: %s", state2str(lpn->state));
#endif
@ -758,6 +761,7 @@ static void lpn_timeout(struct ble_npl_event *work)
}
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:
@ -940,6 +944,8 @@ 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
@ -954,6 +960,10 @@ 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();
}
if (lpn_cb) {
lpn_cb(lpn->frnd, true);
}

View File

@ -6,15 +6,14 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_LOG
#include <stdbool.h>
#include <errno.h>
#include "os/os_mbuf.h"
#include "mesh/mesh.h"
#include "syscfg/syscfg.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG))
#include "host/ble_hs_log.h"
#include "host/ble_uuid.h"
#include "adv.h"
@ -50,7 +49,7 @@ int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
}
if ((MYNEWT_VAL(BLE_MESH_PB_GATT))) {
if (bt_mesh_proxy_prov_disable() == 0) {
if (bt_mesh_proxy_prov_disable(false) == 0) {
pb_gatt_enabled = true;
} else {
pb_gatt_enabled = false;
@ -88,6 +87,26 @@ int bt_mesh_provision(const u8_t net_key[16], u16_t net_idx,
return 0;
}
int bt_mesh_provision_adv(const u8_t uuid[16], u16_t net_idx, u16_t addr,
u8_t attention_duration)
{
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
return -EINVAL;
}
if (bt_mesh_subnet_get(net_idx) == NULL) {
return -EINVAL;
}
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
IS_ENABLED(CONFIG_BT_MESH_PB_ADV)) {
return bt_mesh_pb_adv_open(uuid, net_idx, addr,
attention_duration);
}
return -ENOTSUP;
}
void bt_mesh_reset(void)
{
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
@ -149,14 +168,12 @@ int bt_mesh_prov_enable(bt_mesh_prov_bearer_t bearers)
return -EALREADY;
}
if (MYNEWT_VAL(BLE_MESH_DEBUG)) {
char uuid_buf[BLE_UUID_STR_LEN];
const struct bt_mesh_prov *prov = bt_mesh_prov_get();
ble_uuid_t *uuid = BLE_UUID128_DECLARE();
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));
}
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)) {
@ -189,8 +206,7 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers)
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) &&
(bearers & BT_MESH_PROV_GATT)) {
bt_mesh_proxy_prov_disable();
bt_mesh_adv_update();
bt_mesh_proxy_prov_disable(true);
}
return 0;

View File

@ -32,6 +32,7 @@ struct bt_mesh_net;
#define OP_LIGHT_LIGHTNESS_GET BT_MESH_MODEL_OP_2(0x82, 0x4b)
#define OP_LIGHT_LIGHTNESS_SET BT_MESH_MODEL_OP_2(0x82, 0x4c)
#define OP_LIGHT_LIGHTNESS_SET_UNACK BT_MESH_MODEL_OP_2(0x82, 0x4d)
#define OP_LIGHT_LIGHTNESS_STATUS BT_MESH_MODEL_OP_2(0x82, 0x4e)
bool bt_mesh_is_provisioned(void);

View File

@ -4,16 +4,17 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include <mesh/mesh.h>
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_MODEL))
#include "mesh/mesh.h"
#include "mesh/model_cli.h"
#include "mesh_priv.h"
static s32_t msg_timeout = K_SECONDS(5);
struct bt_mesh_gen_model_cli gen_onoff_cli;
struct bt_mesh_gen_model_cli gen_level_cli;
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;
@ -90,11 +91,53 @@ const struct bt_mesh_model_op gen_onoff_cli_op[] = {
BT_MESH_MODEL_OP_END,
};
static int onoff_cli_init(struct bt_mesh_model *model)
{
BT_DBG("");
if (!model->user_data) {
BT_ERR("No Generic OnOff Client context provided");
return -EINVAL;
}
gen_onoff_cli = model->user_data;
gen_onoff_cli->model = model;
k_sem_init(&gen_onoff_cli->op_sync, 0, 1);
return 0;
}
const struct bt_mesh_model_cb bt_mesh_gen_onoff_cli_cb = {
.init = onoff_cli_init,
};
const struct bt_mesh_model_op gen_level_cli_op[] = {
{ OP_GEN_LEVEL_STATUS, 2, gen_level_status },
BT_MESH_MODEL_OP_END,
};
static int level_cli_init(struct bt_mesh_model *model)
{
BT_DBG("");
if (!model->user_data) {
BT_ERR("No Generic Level Client context provided");
return -EINVAL;
}
gen_level_cli = model->user_data;
gen_level_cli->model = model;
k_sem_init(&gen_level_cli->op_sync, 0, 1);
return 0;
}
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)
{
int err;
@ -129,13 +172,13 @@ int bt_mesh_gen_onoff_get(u16_t net_idx, u16_t addr, u16_t app_idx,
bt_mesh_model_msg_init(msg, OP_GEN_ONOFF_GET);
err = bt_mesh_model_send(gen_onoff_cli.model, &ctx, msg, NULL, NULL);
err = bt_mesh_model_send(gen_onoff_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
goto done;
}
err = cli_wait(&gen_onoff_cli, &param, OP_GEN_ONOFF_STATUS);
err = cli_wait(gen_onoff_cli, &param, OP_GEN_ONOFF_STATUS);
done:
os_mbuf_free_chain(msg);
return err;
@ -165,7 +208,7 @@ int bt_mesh_gen_onoff_set(u16_t net_idx, u16_t addr, u16_t app_idx,
net_buf_simple_add_u8(msg, val);
net_buf_simple_add_u8(msg, transaction_id);
err = bt_mesh_model_send(gen_onoff_cli.model, &ctx, msg, NULL, NULL);
err = bt_mesh_model_send(gen_onoff_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
goto done;
@ -175,7 +218,7 @@ int bt_mesh_gen_onoff_set(u16_t net_idx, u16_t addr, u16_t app_idx,
goto done;
}
err = cli_wait(&gen_onoff_cli, &param, OP_GEN_ONOFF_STATUS);
err = cli_wait(gen_onoff_cli, &param, OP_GEN_ONOFF_STATUS);
done:
if (err == 0) {
transaction_id++;
@ -201,13 +244,13 @@ int bt_mesh_gen_level_get(u16_t net_idx, u16_t addr, u16_t app_idx,
bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_GET);
err = bt_mesh_model_send(gen_level_cli.model, &ctx, msg, NULL, NULL);
err = bt_mesh_model_send(gen_level_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
goto done;
}
err = cli_wait(&gen_level_cli, &param, OP_GEN_LEVEL_STATUS);
err = cli_wait(gen_level_cli, &param, OP_GEN_LEVEL_STATUS);
done:
os_mbuf_free_chain(msg);
return err;
@ -237,7 +280,7 @@ int bt_mesh_gen_level_set(u16_t net_idx, u16_t addr, u16_t app_idx,
net_buf_simple_add_le16(msg, val);
net_buf_simple_add_u8(msg, transaction_id);
err = bt_mesh_model_send(gen_level_cli.model, &ctx, msg, NULL, NULL);
err = bt_mesh_model_send(gen_level_cli->model, &ctx, msg, NULL, NULL);
if (err) {
BT_ERR("model_send() failed (err %d)", err);
goto done;
@ -247,7 +290,7 @@ int bt_mesh_gen_level_set(u16_t net_idx, u16_t addr, u16_t app_idx,
goto done;
}
err = cli_wait(&gen_level_cli, &param, OP_GEN_LEVEL_STATUS);
err = cli_wait(gen_level_cli, &param, OP_GEN_LEVEL_STATUS);
done:
if (err == 0) {
transaction_id++;
@ -256,21 +299,3 @@ done:
return err;
}
int bt_mesh_gen_model_cli_init(struct bt_mesh_model *model, bool primary)
{
struct bt_mesh_gen_model_cli *cli = model->user_data;
BT_DBG("primary %u", primary);
if (!cli) {
BT_ERR("No Generic Model Client context provided");
return -EINVAL;
}
cli->model = model;
k_sem_init(&cli->op_sync, 0, 1);
return 0;
}

View File

@ -4,17 +4,21 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_MODEL_LOG
#include "mesh/mesh.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_MODEL))
#include "mesh/model_srv.h"
#include "mesh_priv.h"
static struct bt_mesh_gen_onoff_srv *gen_onoff_srv;
static struct bt_mesh_gen_level_srv *gen_level_srv;
static struct bt_mesh_light_lightness_srv *light_lightness_srv;
static void gen_onoff_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
struct bt_mesh_gen_onoff_srv_cb *cb = model->user_data;
struct bt_mesh_gen_onoff_srv *cb = model->user_data;
struct os_mbuf *msg = NET_BUF_SIMPLE(3);
u8_t *state;
@ -46,7 +50,7 @@ static void gen_onoff_set_unack(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx,
struct os_mbuf *buf)
{
struct bt_mesh_gen_onoff_srv_cb *cb = model->user_data;
struct bt_mesh_gen_onoff_srv *cb = model->user_data;
u8_t state;
state = buf->om_data[0];
@ -71,7 +75,7 @@ static void gen_onoff_set(struct bt_mesh_model *model,
static void gen_level_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
struct bt_mesh_gen_level_srv_cb *cb = model->user_data;
struct bt_mesh_gen_level_srv *cb = model->user_data;
struct os_mbuf *msg = NET_BUF_SIMPLE(4);
s16_t *level;
@ -102,7 +106,7 @@ static void gen_level_get(struct bt_mesh_model *model,
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 *cb = model->user_data;
struct bt_mesh_gen_level_srv *cb = model->user_data;
s16_t level;
level = (s16_t) net_buf_simple_pull_le16(buf);
@ -124,11 +128,11 @@ static void gen_level_set(struct bt_mesh_model *model,
static void light_lightness_status(struct bt_mesh_model *model,
struct bt_mesh_msg_ctx *ctx)
{
struct bt_mesh_light_lightness_srv_cb *cb = model->user_data;
struct bt_mesh_light_lightness_srv *cb = model->user_data;
struct os_mbuf *msg = NET_BUF_SIMPLE(4);
s16_t *lightness;
bt_mesh_model_msg_init(msg, OP_GEN_LEVEL_STATUS);
bt_mesh_model_msg_init(msg, OP_LIGHT_LIGHTNESS_STATUS);
lightness = net_buf_simple_add(msg, 2);
if (cb && cb->get) {
cb->get(model, lightness);
@ -155,7 +159,7 @@ static void light_lightness_get(struct bt_mesh_model *model,
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 *cb = model->user_data;
struct bt_mesh_light_lightness_srv *cb = model->user_data;
s16_t lightness;
lightness = (s16_t) net_buf_simple_pull_le16(buf);
@ -194,3 +198,69 @@ const struct bt_mesh_model_op light_lightness_srv_op[] = {
{ OP_LIGHT_LIGHTNESS_SET_UNACK, 3, light_lightness_set_unack },
BT_MESH_MODEL_OP_END,
};
static int onoff_srv_init(struct bt_mesh_model *model)
{
struct bt_mesh_gen_onoff_srv *cfg = model->user_data;
BT_DBG("");
if (!cfg) {
BT_ERR("No Generic OnOff Server context provided");
return -EINVAL;
}
cfg->model = model;
gen_onoff_srv = cfg;
return 0;
}
const struct bt_mesh_model_cb gen_onoff_srv_cb = {
.init = onoff_srv_init,
};
static int level_srv_init(struct bt_mesh_model *model)
{
struct bt_mesh_gen_level_srv *cfg = model->user_data;
BT_DBG("");
if (!cfg) {
BT_ERR("No Generic Level Server context provided");
return -EINVAL;
}
cfg->model = model;
gen_level_srv = cfg;
return 0;
}
const struct bt_mesh_model_cb gen_level_srv_cb = {
.init = level_srv_init,
};
static int lightness_srv_init(struct bt_mesh_model *model)
{
struct bt_mesh_light_lightness_srv *cfg = model->user_data;
BT_DBG("");
if (!cfg) {
BT_ERR("No Light Lightness Server context provided");
return -EINVAL;
}
cfg->model = model;
light_lightness_srv = cfg;
return 0;
}
const struct bt_mesh_model_cb light_lightness_srv_cb = {
.init = lightness_srv_init,
};

View File

@ -6,6 +6,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_NET_LOG
#include <string.h>
#include <errno.h>
#include <stdbool.h>
@ -13,10 +16,6 @@
#include "os/os_mbuf.h"
#include "mesh/mesh.h"
#include "syscfg/syscfg.h"
#define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_NET)
#include "host/ble_hs_log.h"
#include "crypto.h"
#include "adv.h"
#include "mesh_priv.h"
@ -60,9 +59,7 @@
#define FRIEND_CRED_COUNT 0
#endif
#if FRIEND_CRED_COUNT > 0
static struct friend_cred friend_cred[FRIEND_CRED_COUNT];
#endif
static u64_t msg_cache[MYNEWT_VAL(BLE_MESH_MSG_CACHE_SIZE)];
static u16_t msg_cache_next;
@ -80,6 +77,13 @@ struct bt_mesh_net bt_mesh = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
.nodes = {
[0 ... (CONFIG_BT_MESH_NODE_COUNT - 1)] = {
.net_idx = BT_MESH_KEY_UNUSED,
}
},
#endif
};
static u32_t dup_cache[4];
@ -131,7 +135,8 @@ static bool msg_cache_match(struct bt_mesh_net_rx *rx,
}
/* Add to the cache */
msg_cache[msg_cache_next++] = hash;
rx->msg_cache_idx = msg_cache_next++;
msg_cache[rx->msg_cache_idx] = hash;
msg_cache_next %= ARRAY_SIZE(msg_cache);
return false;
@ -203,8 +208,6 @@ int bt_mesh_net_keys_create(struct bt_mesh_subnet_keys *keys,
return 0;
}
#if ((MYNEWT_VAL(BLE_MESH_LOW_POWER)) || \
(MYNEWT_VAL(BLE_MESH_FRIEND)))
int friend_cred_set(struct friend_cred *cred, u8_t idx, const u8_t net_key[16])
{
u16_t lpn_addr, frnd_addr;
@ -251,7 +254,8 @@ 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 i;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct friend_cred *cred = &friend_cred[i];
@ -261,6 +265,7 @@ void friend_cred_refresh(u16_t net_idx)
sizeof(cred->cred[0]));
}
}
#pragma GCC diagnostic pop
}
int friend_cred_update(struct bt_mesh_subnet *sub)
@ -268,7 +273,8 @@ int friend_cred_update(struct bt_mesh_subnet *sub)
int err, i;
BT_DBG("net_idx 0x%04x", sub->net_idx);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct friend_cred *cred = &friend_cred[i];
@ -282,7 +288,7 @@ int friend_cred_update(struct bt_mesh_subnet *sub)
return err;
}
}
#pragma GCC diagnostic pop
return 0;
}
@ -293,7 +299,8 @@ struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr,
int i, err;
BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
for (cred = NULL, i = 0; i < ARRAY_SIZE(friend_cred); i++) {
if ((friend_cred[i].addr == BT_MESH_ADDR_UNASSIGNED) ||
(friend_cred[i].addr == addr &&
@ -302,7 +309,7 @@ struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr,
break;
}
}
#pragma GCC diagnostic pop
if (!cred) {
BT_WARN("No free friend credential slots");
return NULL;
@ -342,7 +349,8 @@ void friend_cred_clear(struct friend_cred *cred)
int friend_cred_del(u16_t net_idx, u16_t addr)
{
int i;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct friend_cred *cred = &friend_cred[i];
@ -351,7 +359,7 @@ int friend_cred_del(u16_t net_idx, u16_t addr)
return 0;
}
}
#pragma GCC diagnostic pop
return -ENOENT;
}
@ -361,7 +369,8 @@ int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
int i;
BT_DBG("net_idx 0x%04x addr 0x%04x", sub->net_idx, addr);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct friend_cred *cred = &friend_cred[i];
@ -387,16 +396,9 @@ int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
return 0;
}
#pragma GCC diagnostic pop
return -ENOENT;
}
#else
int friend_cred_get(struct bt_mesh_subnet *sub, u16_t addr, u8_t *nid,
const u8_t **enc, const u8_t **priv)
{
return -ENOENT;
}
#endif /* FRIEND || LOW_POWER */
u8_t bt_mesh_net_flags(struct bt_mesh_subnet *sub)
{
@ -719,6 +721,14 @@ u32_t bt_mesh_next_seq(void)
bt_mesh_store_seq();
}
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) &&
bt_mesh.seq > IV_UPDATE_SEQ_LIMIT &&
bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY)) {
bt_mesh_beacon_ivu_initiator(true);
bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true);
bt_mesh_net_sec_update(NULL);
}
return seq;
}
@ -728,6 +738,7 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct os_mbuf *buf,
{
const u8_t *enc, *priv;
u32_t seq;
u16_t dst;
int err;
BT_DBG("net_idx 0x%04x new_key %u len %u", sub->net_idx, new_key,
@ -753,6 +764,9 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct os_mbuf *buf,
buf->om_data[3] = seq >> 8;
buf->om_data[4] = seq;
/* Get destination, in case it's a proxy client */
dst = DST(buf->om_data);
err = bt_mesh_net_encrypt(enc, buf, BT_MESH_NET_IVI_TX, false);
if (err) {
BT_ERR("encrypt failed (err %d)", err);
@ -765,13 +779,11 @@ int bt_mesh_net_resend(struct bt_mesh_subnet *sub, struct os_mbuf *buf,
return err;
}
bt_mesh_adv_send(buf, cb, cb_data);
if (!atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) &&
bt_mesh.seq > IV_UPDATE_SEQ_LIMIT) {
bt_mesh_beacon_ivu_initiator(true);
bt_mesh_net_iv_update(bt_mesh.iv_index + 1, true);
bt_mesh_net_sec_update(NULL);
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) &&
bt_mesh_proxy_relay(buf, dst)) {
send_cb_finalize(cb, cb_data);
} else {
bt_mesh_adv_send(buf, cb, cb_data);
}
return 0;
@ -886,15 +898,7 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct os_mbuf *buf,
/* Notify completion if this only went
* through the Mesh Proxy.
*/
if (cb) {
if (cb->start) {
cb->start(0, 0, cb_data);
}
if (cb->end) {
cb->end(0, cb_data);
}
}
send_cb_finalize(cb, cb_data);
err = 0;
goto done;
@ -1019,8 +1023,6 @@ static int net_decrypt(struct bt_mesh_subnet *sub, const u8_t *enc,
return bt_mesh_net_decrypt(enc, buf, BT_MESH_NET_IVI_RX(rx), false);
}
#if (MYNEWT_VAL(BLE_MESH_LOW_POWER) || \
MYNEWT_VAL(BLE_MESH_FRIEND))
static int friend_decrypt(struct bt_mesh_subnet *sub, const u8_t *data,
size_t data_len, struct bt_mesh_net_rx *rx,
struct os_mbuf *buf)
@ -1028,7 +1030,8 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const u8_t *data,
int i;
BT_DBG("NID 0x%02x net_idx 0x%04x", NID(data), sub->net_idx);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits"
for (i = 0; i < ARRAY_SIZE(friend_cred); i++) {
struct friend_cred *cred = &friend_cred[i];
@ -1053,10 +1056,9 @@ static int friend_decrypt(struct bt_mesh_subnet *sub, const u8_t *data,
return 0;
}
}
#pragma GCC diagnostic pop
return -ENOENT;
}
#endif
static bool net_find_and_decrypt(const u8_t *data, size_t data_len,
struct bt_mesh_net_rx *rx,
@ -1073,15 +1075,14 @@ static bool net_find_and_decrypt(const u8_t *data, size_t data_len,
continue;
}
#if (MYNEWT_VAL(BLE_MESH_LOW_POWER) || \
MYNEWT_VAL(BLE_MESH_FRIEND))
if (!friend_decrypt(sub, data, data_len, rx, buf)) {
rx->friend_cred = 1;
if ((IS_ENABLED(CONFIG_BT_MESH_LOW_POWER) ||
IS_ENABLED(CONFIG_BT_MESH_FRIEND)) &&
!friend_decrypt(sub, data, data_len, rx, buf)) {
rx->friend_cred = 1U;
rx->ctx.net_idx = sub->net_idx;
rx->sub = sub;
return true;
}
#endif
if (NID(data) == sub->keys[0].nid &&
!net_decrypt(sub, sub->keys[0].enc, sub->keys[0].privacy,
@ -1233,6 +1234,17 @@ done:
net_buf_unref(buf);
}
void bt_mesh_net_header_parse(struct os_mbuf *buf,
struct bt_mesh_net_rx *rx)
{
rx->old_iv = (IVI(buf->om_data) != (bt_mesh.iv_index & 0x01));
rx->ctl = CTL(buf->om_data);
rx->ctx.recv_ttl = TTL(buf->om_data);
rx->seq = SEQ(buf->om_data);
rx->ctx.addr = SRC(buf->om_data);
rx->ctx.recv_dst = DST(buf->om_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)
{
@ -1303,7 +1315,7 @@ void bt_mesh_net_recv(struct os_mbuf *data, s8_t rssi,
enum bt_mesh_net_if net_if)
{
struct os_mbuf *buf = NET_BUF_SIMPLE(29);
struct bt_mesh_net_rx rx = { .rssi = rssi };
struct bt_mesh_net_rx rx = { .ctx.recv_rssi = rssi };
struct net_buf_simple_state state;
BT_DBG("rssi %d net_if %u", rssi, net_if);
@ -1320,15 +1332,33 @@ void bt_mesh_net_recv(struct os_mbuf *data, s8_t rssi,
/* Save the state so the buffer can later be relayed */
net_buf_simple_save(buf, &state);
if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY)) &&
net_if == BT_MESH_NET_IF_PROXY) {
bt_mesh_proxy_addr_add(data, rx.ctx.addr);
}
rx.local_match = (bt_mesh_fixed_group_match(rx.ctx.recv_dst) ||
bt_mesh_elem_find(rx.ctx.recv_dst));
bt_mesh_trans_recv(buf, &rx);
if ((MYNEWT_VAL(BLE_MESH_GATT_PROXY)) &&
net_if == BT_MESH_NET_IF_PROXY) {
bt_mesh_proxy_addr_add(data, rx.ctx.addr);
if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_DISABLED &&
!rx.local_match) {
BT_INFO("Proxy is disabled; ignoring message");
goto done;
}
}
/* The transport layer has indicated that it has rejected the message,
* but would like to see it again if it is received in the future.
* This can happen if a message is received when the device is in
* Low Power mode, but the message was not encrypted with the friend
* credentials. Remove it from the message cache so that we accept
* it again in the future.
*/
if (bt_mesh_trans_recv(buf, &rx) == -EAGAIN) {
BT_WARN("Removing rejected message from Network Message Cache");
msg_cache[rx.msg_cache_idx] = 0ULL;
/* Rewind the next index now that we're not using this entry */
msg_cache_next = rx.msg_cache_idx;
}
/* Relay if this was a group/virtual address, or if the destination
* was neither a local element nor an LPN we're Friends for.

View File

@ -41,6 +41,13 @@ struct bt_mesh_app_key {
} keys[2];
};
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
@ -78,7 +85,7 @@ struct bt_mesh_subnet {
struct bt_mesh_rpl {
u16_t src;
bool old_iv;
#if defined(CONFIG_BT_SETTINGS)
#if (MYNEWT_VAL(BLE_MESH_SETTINGS))
bool store;
#endif
u32_t seq;
@ -115,6 +122,12 @@ struct bt_mesh_friend {
struct bt_mesh_friend_seg {
struct net_buf_slist_t queue;
/* The target number of segments, i.e. not necessarily
* the current number of segments, in the queue. This is
* used for Friend Queue free space calculations.
*/
u8_t seg_count;
} seg[FRIEND_SEG_RX];
struct os_mbuf *last;
@ -208,7 +221,7 @@ enum {
BT_MESH_IVU_TEST, /* IV Update test mode */
BT_MESH_IVU_PENDING, /* Update blocked by SDU in progress */
/* pending storage actions */
/* pending storage actions, must reside within first 32 flags */
BT_MESH_RPL_PENDING,
BT_MESH_KEYS_PENDING,
BT_MESH_NET_PENDING,
@ -217,6 +230,8 @@ enum {
BT_MESH_HB_PUB_PENDING,
BT_MESH_CFG_PENDING,
BT_MESH_MOD_PENDING,
BT_MESH_VA_PENDING,
BT_MESH_NODES_PENDING,
/* Don't touch - intentionally last */
BT_MESH_FLAG_COUNT,
@ -249,6 +264,10 @@ struct bt_mesh_net {
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)];
@ -276,7 +295,7 @@ struct bt_mesh_net_rx {
net_if:2, /* Network interface */
local_match:1, /* Matched a local element */
friend_match:1; /* Matched an LPN we're friends for */
s8_t rssi;
u16_t msg_cache_idx; /* Index of entry in message cache */
};
/* Encoding context for Network/Transport data */
@ -346,6 +365,8 @@ u32_t bt_mesh_next_seq(void);
void bt_mesh_net_start(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 {
@ -372,4 +393,20 @@ struct friend_cred *friend_cred_create(struct bt_mesh_subnet *sub, u16_t addr,
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)
{
if (!cb) {
return;
}
if (cb->start) {
cb->start(0, 0, cb_data);
}
if (cb->end) {
cb->end(0, cb_data);
}
}
#endif

View File

@ -0,0 +1,161 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_PROV_LOG
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
#include "mesh/mesh.h"
#include "mesh_priv.h"
#include "net.h"
#include "access.h"
#include "settings.h"
/*
* 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(u16_t addr_start, u8_t num_elem, u16_t *next)
{
const struct bt_mesh_comp *comp = bt_mesh_comp_get();
u16_t addr_end = addr_start + num_elem - 1;
u16_t other_start, other_end;
int i;
if (comp == NULL) {
return -EINVAL;
}
if (!BT_MESH_ADDR_IS_UNICAST(addr_start) ||
!BT_MESH_ADDR_IS_UNICAST(addr_end) ||
num_elem == 0 || next == NULL) {
return -EINVAL;
}
other_start = bt_mesh_primary_addr();
other_end = other_start + comp->elem_count - 1;
/* Compare with local element addresses */
if (!(addr_end < other_start || addr_start > other_end)) {
*next = other_end + 1;
return -EAGAIN;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
struct bt_mesh_node *node = &bt_mesh.nodes[i];
if (node->net_idx == BT_MESH_KEY_UNUSED) {
continue;
}
other_start = node->addr;
other_end = other_start + node->num_elem - 1;
if (!(addr_end < other_start || addr_start > other_end)) {
*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 u16_t find_lowest_free_addr(u8_t num_elem)
{
u16_t addr = 1, next;
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.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;
}
struct bt_mesh_node *bt_mesh_node_find(u16_t addr)
{
int i;
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
struct bt_mesh_node *node = &bt_mesh.nodes[i];
if (addr >= node->addr &&
addr <= node->addr + node->num_elem - 1) {
return node;
}
}
return NULL;
}
struct bt_mesh_node *bt_mesh_node_alloc(u16_t addr, u8_t num_elem,
u16_t net_idx)
{
int i;
BT_DBG("");
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)) {
return NULL;
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.nodes); i++) {
struct bt_mesh_node *node = &bt_mesh.nodes[i];
if (node->addr == BT_MESH_ADDR_UNASSIGNED) {
node->addr = addr;
node->num_elem = num_elem;
node->net_idx = net_idx;
return node;
}
}
return NULL;
}
void bt_mesh_node_del(struct bt_mesh_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_node(node);
}
node->addr = BT_MESH_ADDR_UNASSIGNED;
(void)memset(node->dev_key, 0, sizeof(node->dev_key));
}
#endif

View File

@ -0,0 +1,10 @@
/*
* Copyright (c) 2019 Tobias Svehagen
*
* SPDX-License-Identifier: Apache-2.0
*/
struct bt_mesh_node *bt_mesh_node_find(u16_t addr);
struct bt_mesh_node *bt_mesh_node_alloc(u16_t addr, u8_t num_elem,
u16_t net_idx);
void bt_mesh_node_del(struct bt_mesh_node *node, bool store);

View File

@ -5,14 +5,14 @@
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_PROV_LOG
#if MYNEWT_VAL(BLE_MESH_PROV)
#include <errno.h>
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_PROV))
#include "host/ble_hs_log.h"
#include "mesh/mesh.h"
#include "mesh_priv.h"
@ -25,6 +25,8 @@
#include "proxy.h"
#include "prov.h"
#include "testing.h"
#include "settings.h"
#include "nodes.h"
/* 3 transmissions, 20ms interval */
#define PROV_XMIT BT_MESH_TRANSMIT(2, 20)
@ -69,6 +71,8 @@
#define PROV_COMPLETE 0x08
#define PROV_FAILED 0x09
#define PROV_NO_PDU 0xff
#define PROV_ALG_P256 0x00
#define GPCF(gpc) (gpc & 0x03)
@ -98,22 +102,40 @@
#define XACT_NVAL 0xff
enum {
REMOTE_PUB_KEY, /* Remote key has been received */
WAIT_PUB_KEY, /* Waiting for local PubKey to be generated */
LINK_ACTIVE, /* Link has been opened */
HAVE_DHKEY, /* DHKey has been calculated */
SEND_CONFIRM, /* Waiting to send Confirm value */
LINK_ACK_RECVD, /* Ack for link has been received */
LINK_CLOSING, /* Link is closing down */
SEND_PUB_KEY, /* Waiting to send PubKey */
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. */
LINK_INVALID, /* Error occurred during provisioning */
PROVISIONER, /* The link was opened as provisioner */
NUM_FLAGS,
};
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
#define PROVISIONER_LINK 1
#else
#define PROVISIONER_LINK 0
#endif
struct provisioner_link {
struct bt_mesh_node *node;
u16_t addr;
u16_t net_idx;
u8_t attention_duration;
};
struct prov_link {
ATOMIC_DEFINE(flags, NUM_FLAGS);
#if (MYNEWT_VAL(BLE_MESH_PB_GATT))
uint16_t conn_handle; /* GATT connection */
#endif
struct provisioner_link provisioner[PROVISIONER_LINK];
u8_t dhkey[32]; /* Calculated DHKey */
u8_t expect; /* Next expected PDU */
@ -168,6 +190,7 @@ struct prov_rx {
#define RETRANSMIT_TIMEOUT K_MSEC(500)
#define BUF_TIMEOUT K_MSEC(400)
#define CLOSING_TIMEOUT K_SECONDS(3)
#define TRANSACTION_TIMEOUT K_SECONDS(30)
#define PROTOCOL_TIMEOUT K_SECONDS(60)
@ -200,6 +223,11 @@ static int reset_state(void)
bt_mesh_attention(NULL, 0);
}
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
link.provisioner->node != NULL) {
bt_mesh_node_del(link.provisioner->node, false);
}
#if (MYNEWT_VAL(BLE_MESH_PB_ADV))
/* Clear everything except the retransmit and protocol timer
* delayed work objects.
@ -210,6 +238,9 @@ static int reset_state(void)
#if (MYNEWT_VAL(BLE_MESH_PB_GATT))
link.rx.buf = bt_mesh_proxy_get_buf();
#else
if (!rx_buf) {
rx_buf = NET_BUF_SIMPLE(65);
}
net_buf_simple_init(rx_buf, 0);
link.rx.buf = rx_buf;
#endif /* PB_GATT */
@ -364,7 +395,7 @@ static void send_reliable(void)
}
}
static int bearer_ctl_send(u8_t op, void *data, u8_t data_len)
static int bearer_ctl_send(u8_t op, const void *data, u8_t data_len)
{
struct os_mbuf *buf;
@ -402,11 +433,20 @@ static u8_t last_seg(u8_t len)
static inline u8_t next_transaction_id(void)
{
if (link.tx.id != 0 && link.tx.id != 0xFF) {
return ++link.tx.id;
if (atomic_test_bit(link.flags, PROVISIONER)) {
if (link.tx.id != 0x7F) {
link.tx.id++;
} else {
link.tx.id = 0;
}
} else {
if (link.tx.id != 0U && link.tx.id != 0xFF) {
link.tx.id++;
} else {
link.tx.id = 0x80;
}
}
link.tx.id = 0x80;
return link.tx.id;
}
@ -576,10 +616,63 @@ done:
os_mbuf_free_chain(buf);
}
#if MYNEWT_VAL(BLE_MESH_PB_ADV)
static void send_invite(void)
{
struct os_mbuf *inv = PROV_BUF(2);
BT_DBG("");
prov_buf_init(inv, PROV_INVITE);
net_buf_simple_add_u8(inv, link.provisioner->attention_duration);
link.conf_inputs[0] = link.provisioner->attention_duration;
if (prov_send(inv)) {
BT_ERR("Failed to send invite");
goto done;
}
link.expect = PROV_CAPABILITIES;
done:
os_mbuf_free_chain(inv);
}
#endif
static void send_start(void)
{
struct os_mbuf *start = PROV_BUF(6);
BT_DBG("");
prov_buf_init(start, PROV_START);
net_buf_simple_add_u8(start, PROV_ALG_P256);
net_buf_simple_add_u8(start, PUB_KEY_NO_OOB);
net_buf_simple_add_u8(start, AUTH_METHOD_NO_OOB);
memset(link.auth, 0, sizeof(link.auth));
net_buf_simple_add_u8(start, 0); /* Auth Action */
net_buf_simple_add_u8(start, 0); /* Auth Size */
memcpy(&link.conf_inputs[12], &start->om_data[1], 5);
if (prov_send(start)) {
BT_ERR("Failed to send start");
}
os_mbuf_free_chain(start);
}
static void prov_capabilities(const u8_t *data)
{
u16_t algorithms, output_action, input_action;
if (!IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) {
return;
}
BT_DBG("Elements: %u", data[0]);
algorithms = sys_get_be16(&data[1]);
@ -596,6 +689,26 @@ static void prov_capabilities(const u8_t *data)
input_action = sys_get_be16(&data[9]);
BT_DBG("Input OOB Action: 0x%04x", input_action);
if (data[0] == 0) {
BT_ERR("Invalid number of elements");
prov_send_fail_msg(PROV_ERR_NVAL_FMT);
return;
}
link.provisioner->node = bt_mesh_node_alloc(link.provisioner->addr,
data[0],
link.provisioner->net_idx);
if (link.provisioner->node == NULL) {
prov_send_fail_msg(PROV_ERR_RESOURCES);
return;
}
memcpy(&link.conf_inputs[1], data, 11);
atomic_set_bit(link.flags, SEND_PUB_KEY);
send_start();
}
static bt_mesh_output_action_t output_action(u8_t action)
@ -669,6 +782,8 @@ static int prov_auth(u8_t method, u8_t action, u8_t size)
return -EINVAL;
}
atomic_set_bit(link.flags, NOTIFY_INPUT_COMPLETE);
if (output == BT_MESH_DISPLAY_STRING) {
unsigned char str[9];
u8_t i;
@ -810,7 +925,11 @@ static void send_confirm(void)
goto done;
}
link.expect = PROV_RANDOM;
if (atomic_test_bit(link.flags, PROVISIONER)) {
link.expect = PROV_CONFIRM;
} else {
link.expect = PROV_RANDOM;
}
done:
os_mbuf_free_chain(cfm);
@ -824,6 +943,7 @@ static void send_input_complete(void)
if (prov_send(buf)) {
BT_ERR("Failed to send Provisioning Input Complete");
}
link.expect = PROV_CONFIRM;
os_mbuf_free_chain(buf);
}
@ -840,14 +960,6 @@ int bt_mesh_input_number(u32_t num)
send_input_complete();
if (!atomic_test_bit(link.flags, HAVE_DHKEY)) {
return 0;
}
if (atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) {
send_confirm();
}
return 0;
}
@ -863,43 +975,9 @@ int bt_mesh_input_string(const char *str)
send_input_complete();
if (!atomic_test_bit(link.flags, HAVE_DHKEY)) {
return 0;
}
if (atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) {
send_confirm();
}
return 0;
}
static void prov_dh_key_cb(const u8_t key[32])
{
BT_DBG("%p", key);
if (!key) {
BT_ERR("DHKey generation failed");
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
return;
}
sys_memcpy_swap(link.dhkey, key, 32);
BT_DBG("DHkey: %s", bt_hex(link.dhkey, 32));
atomic_set_bit(link.flags, HAVE_DHKEY);
if (atomic_test_bit(link.flags, WAIT_NUMBER) ||
atomic_test_bit(link.flags, WAIT_STRING)) {
return;
}
if (atomic_test_and_clear_bit(link.flags, SEND_CONFIRM)) {
send_confirm();
}
}
static void send_pub_key(void)
{
struct os_mbuf *buf = PROV_BUF(65);
@ -914,56 +992,112 @@ static void send_pub_key(void)
BT_DBG("Local Public Key: %s", bt_hex(key, 64));
/* Copy remote key in little-endian for bt_dh_key_gen().
* X and Y halves are swapped independently. Use response
* buffer as a temporary storage location. The bt_dh_key_gen()
* will also take care of validating the remote public key.
*/
sys_memcpy_swap(buf->om_data, &link.conf_inputs[17], 32);
sys_memcpy_swap(&buf->om_data[32], &link.conf_inputs[49], 32);
if (bt_dh_key_gen(buf->om_data, prov_dh_key_cb)) {
BT_ERR("Failed to generate DHKey");
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
return;
}
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);
memcpy(&link.conf_inputs[81], &buf->om_data[1], 64);
if (atomic_test_bit(link.flags, PROVISIONER)) {
/* PublicKeyProvisioner */
memcpy(&link.conf_inputs[17], &buf->om_data[1], 64);
} else {
/* PublicKeyRemote */
memcpy(&link.conf_inputs[81], &buf->om_data[1], 64);
}
if (prov_send(buf)) {
BT_ERR("Failed to send Public Key");
return;
goto done;
}
link.expect = PROV_CONFIRM;
if (atomic_test_bit(link.flags, PROVISIONER)) {
link.expect = PROV_PUB_KEY;
} else {
if (atomic_test_bit(link.flags, WAIT_NUMBER) ||
atomic_test_bit(link.flags, WAIT_STRING)) {
link.expect = PROV_NO_PDU; /* Wait for input */
} else {
link.expect = PROV_CONFIRM;
}
}
done:
os_mbuf_free_chain(buf);
}
static void prov_dh_key_cb(const u8_t dhkey[32])
{
BT_DBG("%p", dhkey);
if (!dhkey) {
BT_ERR("DHKey generation failed");
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
return;
}
sys_memcpy_swap(link.dhkey, dhkey, 32);
BT_DBG("DHkey: %s", bt_hex(link.dhkey, 32));
if (atomic_test_bit(link.flags, PROVISIONER)) {
send_confirm();
} else {
send_pub_key();
}
}
static void prov_dh_key_gen(void)
{
u8_t remote_pk_le[64], *remote_pk;
if (atomic_test_bit(link.flags, PROVISIONER)) {
remote_pk = &link.conf_inputs[81];
} else {
remote_pk = &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_send_fail_msg(PROV_ERR_UNEXP_ERR);
}
}
static void prov_pub_key(const u8_t *data)
{
BT_DBG("Remote Public Key: %s", bt_hex(data, 64));
memcpy(&link.conf_inputs[17], data, 64);
if (atomic_test_bit(link.flags, PROVISIONER)) {
/* PublicKeyDevice */
memcpy(&link.conf_inputs[81], data, 64);
if (!bt_pub_key_get()) {
/* Clear retransmit timer */
#if (MYNEWT_VAL(BLE_MESH_PB_ADV))
prov_clear_tx();
#endif
atomic_set_bit(link.flags, REMOTE_PUB_KEY);
BT_WARN("Waiting for local public key");
return;
} else {
/* PublicKeyProvisioner */
memcpy(&link.conf_inputs[17], data, 64);
if (!bt_pub_key_get()) {
/* Clear retransmit timer */
#if (MYNEWT_VAL(BLE_MESH_PB_ADV))
prov_clear_tx();
#endif
atomic_set_bit(link.flags, WAIT_PUB_KEY);
BT_WARN("Waiting for local public key");
return;
}
}
send_pub_key();
prov_dh_key_gen();
}
static void pub_key_ready(const u8_t *pkey)
@ -975,53 +1109,145 @@ static void pub_key_ready(const u8_t *pkey)
BT_DBG("Local public key ready");
if (atomic_test_and_clear_bit(link.flags, REMOTE_PUB_KEY)) {
send_pub_key();
if (atomic_test_and_clear_bit(link.flags, WAIT_PUB_KEY)) {
if (atomic_test_bit(link.flags, PROVISIONER)) {
send_pub_key();
} else {
prov_dh_key_gen();
}
}
}
static void notify_input_complete(void)
{
if (atomic_test_and_clear_bit(link.flags, NOTIFY_INPUT_COMPLETE) &&
prov->input_complete) {
prov->input_complete();
}
}
static void prov_input_complete(const u8_t *data)
{
BT_DBG("");
notify_input_complete();
}
static void prov_confirm(const u8_t *data)
static void send_prov_data(void)
{
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
struct os_mbuf *pdu = PROV_BUF(34);
struct bt_mesh_subnet *sub;
u8_t session_key[16];
u8_t nonce[13];
int err;
memcpy(link.conf, data, 16);
if (!atomic_test_bit(link.flags, HAVE_DHKEY)) {
#if (MYNEWT_VAL(BLE_MESH_PB_ADV))
prov_clear_tx();
#endif
atomic_set_bit(link.flags, SEND_CONFIRM);
} else {
send_confirm();
}
}
static void prov_random(const u8_t *data)
{
struct os_mbuf *rnd = PROV_BUF(16);
u8_t conf_verify[16];
BT_DBG("Remote Random: %s", bt_hex(data, 16));
if (bt_mesh_prov_conf(link.conf_key, data, link.auth, conf_verify)) {
BT_ERR("Unable to calculate confirmation verification");
err = bt_mesh_session_key(link.dhkey, link.prov_salt, session_key);
if (err) {
BT_ERR("Unable to generate session key");
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
goto done;
}
if (memcmp(conf_verify, link.conf, 16)) {
BT_ERR("Invalid confirmation value");
BT_DBG("Received: %s", bt_hex(link.conf, 16));
BT_DBG("Calculated: %s", bt_hex(conf_verify, 16));
prov_send_fail_msg(PROV_ERR_CFM_FAILED);
BT_DBG("SessionKey: %s", bt_hex(session_key, 16));
err = bt_mesh_prov_nonce(link.dhkey, link.prov_salt, nonce);
if (err) {
BT_ERR("Unable to generate session nonce");
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
goto done;
}
BT_DBG("Nonce: %s", bt_hex(nonce, 13));
err = bt_mesh_dev_key(link.dhkey, link.prov_salt,
link.provisioner->node->dev_key);
if (err) {
BT_ERR("Unable to generate device key");
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
goto done;
}
BT_DBG("DevKey: %s", bt_hex(link.provisioner->node->dev_key, 16));
sub = bt_mesh_subnet_get(link.provisioner->node->net_idx);
if (sub == NULL) {
BT_ERR("No subnet with net_idx %u",
link.provisioner->node->net_idx);
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
goto done;
}
prov_buf_init(pdu, PROV_DATA);
net_buf_simple_add_mem(pdu, sub->keys[sub->kr_flag].net, 16);
net_buf_simple_add_be16(pdu, link.provisioner->node->net_idx);
net_buf_simple_add_u8(pdu, bt_mesh_net_flags(sub));
net_buf_simple_add_be32(pdu, bt_mesh.iv_index);
net_buf_simple_add_be16(pdu, link.provisioner->node->addr);
net_buf_simple_add(pdu, 8); /* For MIC */
BT_DBG("net_idx %u, iv_index 0x%08x, addr 0x%04x",
link.provisioner->node->net_idx, bt_mesh.iv_index,
link.provisioner->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_send_fail_msg(PROV_ERR_DECRYPT);
goto done;
}
if (prov_send(pdu)) {
BT_ERR("Failed to send Provisioning Data");
goto done;
}
link.expect = PROV_COMPLETE;
done:
os_mbuf_free_chain(pdu);
}
static void prov_complete(const u8_t *data)
{
if (!IS_ENABLED(CONFIG_BT_MESH_PROVISIONER)) {
return;
}
struct bt_mesh_node *node = link.provisioner->node;
#if MYNEWT_VAL(BLE_MESH_PB_ADV)
u8_t reason = CLOSE_REASON_SUCCESS;
#endif
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 (IS_ENABLED(CONFIG_BT_SETTINGS)) {
bt_mesh_store_node(node);
}
link.provisioner->node = NULL;
link.expect = PROV_NO_PDU;
atomic_set_bit(link.flags, LINK_CLOSING);
#if MYNEWT_VAL(BLE_MESH_PB_ADV)
bearer_ctl_send(LINK_CLOSE, &reason, sizeof(reason));
#endif
bt_mesh_prov_node_added(node->net_idx, node->addr, node->num_elem);
/*
* 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 instead of resetting the
* link here.
*/
}
static void send_random(void)
{
struct os_mbuf *rnd = PROV_BUF(17);
prov_buf_init(rnd, PROV_RANDOM);
net_buf_simple_add_mem(rnd, link.rand, 16);
@ -1030,19 +1256,75 @@ static void prov_random(const u8_t *data)
goto done;
}
if (bt_mesh_prov_salt(link.conf_salt, data, link.rand,
if (atomic_test_bit(link.flags, PROVISIONER)) {
link.expect = PROV_RANDOM;
} else {
link.expect = PROV_DATA;
}
done:
os_mbuf_free_chain(rnd);
}
static void prov_random(const u8_t *data)
{
u8_t conf_verify[16];
const u8_t *prov_rand, *dev_rand;
BT_DBG("Remote Random: %s", bt_hex(data, 16));
if (bt_mesh_prov_conf(link.conf_key, data, link.auth, conf_verify)) {
BT_ERR("Unable to calculate confirmation verification");
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
return;
}
if (memcmp(conf_verify, link.conf, 16)) {
BT_ERR("Invalid confirmation value");
BT_DBG("Received: %s", bt_hex(link.conf, 16));
BT_DBG("Calculated: %s", bt_hex(conf_verify, 16));
prov_send_fail_msg(PROV_ERR_CFM_FAILED);
return;
}
if (atomic_test_bit(link.flags, PROVISIONER)) {
prov_rand = link.rand;
dev_rand = data;
} else {
prov_rand = data;
dev_rand = link.rand;
}
if (bt_mesh_prov_salt(link.conf_salt, prov_rand, dev_rand,
link.prov_salt)) {
BT_ERR("Failed to generate provisioning salt");
prov_send_fail_msg(PROV_ERR_UNEXP_ERR);
goto done;
return;
}
BT_DBG("ProvisioningSalt: %s", bt_hex(link.prov_salt, 16));
link.expect = PROV_DATA;
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
atomic_test_bit(link.flags, PROVISIONER)) {
send_prov_data();
} else {
send_random();
}
}
done:
os_mbuf_free_chain(rnd);
static void prov_confirm(const u8_t *data)
{
BT_DBG("Remote Confirm: %s", bt_hex(data, 16));
memcpy(link.conf, data, 16);
notify_input_complete();
if (atomic_test_bit(link.flags, PROVISIONER)) {
send_random();
} else {
send_confirm();
}
}
static inline bool is_pb_gatt(void)
@ -1119,7 +1401,7 @@ static void prov_data(const u8_t *data)
}
/* Ignore any further PDUs on this link */
link.expect = 0;
link.expect = PROV_NO_PDU;
/* Store info, since bt_mesh_provision() will end up clearing it */
if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) {
@ -1145,11 +1427,6 @@ done:
os_mbuf_free_chain(msg);
}
static void prov_complete(const u8_t *data)
{
BT_DBG("");
}
static void prov_failed(const u8_t *data)
{
BT_WARN("Error: 0x%02x", data[0]);
@ -1174,7 +1451,7 @@ static const struct {
#if (MYNEWT_VAL(BLE_MESH_PB_ADV))
static void prov_retransmit(struct ble_npl_event *work)
{
int i;
int i, timeout;
BT_DBG("");
@ -1183,7 +1460,13 @@ static void prov_retransmit(struct ble_npl_event *work)
return;
}
if (k_uptime_get() - link.tx.start > TRANSACTION_TIMEOUT) {
if (atomic_test_bit(link.flags, LINK_CLOSING)) {
timeout = CLOSING_TIMEOUT;
} else {
timeout = TRANSACTION_TIMEOUT;
}
if (k_uptime_get() - link.tx.start > timeout) {
BT_WARN("Giving up transaction");
reset_adv_link();
return;
@ -1248,12 +1531,26 @@ static void link_open(struct prov_rx *rx, struct os_mbuf *buf)
bearer_ctl_send(LINK_ACK, NULL, 0);
link.expect = PROV_INVITE;
}
static void link_ack(struct prov_rx *rx, struct os_mbuf *buf)
{
BT_DBG("Link ack: len %u", buf->om_len);
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
atomic_test_bit(link.flags, PROVISIONER)) {
if (atomic_test_and_set_bit(link.flags, LINK_ACK_RECVD)) {
return;
}
prov_clear_tx();
if (prov->link_open) {
prov->link_open(BT_MESH_PROV_ADV);
}
send_invite();
}
}
static void link_close(struct prov_rx *rx, struct os_mbuf *buf)
@ -1398,7 +1695,21 @@ static void gen_prov_ack(struct prov_rx *rx, struct os_mbuf *buf)
}
if (rx->xact_id == link.tx.id) {
prov_clear_tx();
/* Don't clear resending of LINK_CLOSE messages */
if (!atomic_test_bit(link.flags, LINK_CLOSING)) {
prov_clear_tx();
}
/* Send the PubKey when the the Start message is ACK'ed */
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
atomic_test_and_clear_bit(link.flags, SEND_PUB_KEY)) {
if (!bt_pub_key_get()) {
atomic_set_bit(link.flags, WAIT_PUB_KEY);
BT_WARN("Waiting for local public key");
} else {
send_pub_key();
}
}
}
}
@ -1456,9 +1767,9 @@ static void gen_prov_start(struct prov_rx *rx, struct os_mbuf *buf)
}
static const struct {
void (*const func)(struct prov_rx *rx, struct os_mbuf *buf);
const u8_t require_link;
const u8_t min_len;
void (*func)(struct prov_rx *rx, struct os_mbuf *buf);
bool require_link;
u8_t min_len;
} gen_prov[] = {
{ gen_prov_start, true, 3 },
{ gen_prov_ack, true, 0 },
@ -1510,6 +1821,31 @@ void bt_mesh_pb_adv_recv(struct os_mbuf *buf)
gen_prov_recv(&rx, buf);
}
int bt_mesh_pb_adv_open(const u8_t uuid[16], u16_t net_idx, u16_t addr,
u8_t attention_duration)
{
BT_DBG("uuid %s", bt_hex(uuid, 16));
if (atomic_test_and_set_bit(link.flags, LINK_ACTIVE)) {
return -EBUSY;
}
atomic_set_bit(link.flags, PROVISIONER);
bt_rand(&link.id, sizeof(link.id));
link.tx.id = 0x7F;
link.provisioner->addr = addr;
link.provisioner->net_idx = net_idx;
link.provisioner->attention_duration = attention_duration;
net_buf_simple_init(link.rx.buf, 0);
bearer_ctl_send(LINK_OPEN, uuid, 16);
return 0;
}
#endif /* MYNEWT_VAL(BLE_MESH_PB_ADV) */
#if (MYNEWT_VAL(BLE_MESH_PB_GATT))
@ -1655,6 +1991,13 @@ 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)
{
if (prov->node_added) {
prov->node_added(net_idx, addr, num_elem);
}
}
void bt_mesh_prov_reset(void)
{
if (prov->reset) {

View File

@ -13,6 +13,9 @@
#include "mesh/mesh.h"
#include "../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);
void bt_mesh_pb_adv_recv(struct os_mbuf *buf);
bool bt_prov_active(void);
@ -28,6 +31,7 @@ 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_reset(void);
#endif

View File

@ -7,13 +7,11 @@
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_PROXY_LOG
#if MYNEWT_VAL(BLE_MESH_PROXY)
#include "mesh/mesh.h"
#define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_PROXY))
#include "host/ble_hs_log.h"
#include "host/ble_att.h"
#include "services/gatt/ble_svc_gatt.h"
#include "../../host/src/ble_hs_priv.h"
@ -654,10 +652,7 @@ static void proxy_connected(uint16_t conn_handle)
static void proxy_disconnected(uint16_t conn_handle, int reason)
{
int i;
BT_INFO("conn_handle %d reason %d", conn_handle, reason);
conn_count--;
bool disconnected = false;
for (i = 0; i < ARRAY_SIZE(clients); i++) {
struct bt_mesh_proxy_client *client = &clients[i];
@ -670,11 +665,16 @@ 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;
}
}
bt_mesh_adv_update();
if (disconnected) {
BT_INFO("conn_handle %d reason %d", conn_handle, reason);
bt_mesh_adv_update();
}
}
struct os_mbuf *bt_mesh_proxy_get_buf(void)
@ -740,7 +740,7 @@ int bt_mesh_proxy_prov_enable(void)
return 0;
}
int bt_mesh_proxy_prov_disable(void)
int bt_mesh_proxy_prov_disable(bool disconnect)
{
uint16_t handle;
int rc;
@ -767,13 +767,23 @@ int bt_mesh_proxy_prov_disable(void)
for (i = 0; i < ARRAY_SIZE(clients); i++) {
struct bt_mesh_proxy_client *client = &clients[i];
if ((client->conn_handle != BLE_HS_CONN_HANDLE_NONE)
&& (client->filter_type == PROV)) {
if ((client->conn_handle == BLE_HS_CONN_HANDLE_NONE)
|| (client->filter_type != PROV)) {
continue;
}
if (disconnect) {
rc = ble_gap_terminate(client->conn_handle,
BLE_ERR_REM_USER_CONN_TERM);
assert(rc == 0);
} else {
bt_mesh_pb_gatt_close(client->conn_handle);
client->filter_type = NONE;
}
}
bt_mesh_adv_update();
return 0;
}
#endif /* MYNEWT_VAL(BLE_MESH_PB_GATT) */
@ -907,16 +917,6 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client,
BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr);
if (client->filter_type == WHITELIST) {
for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
if (client->filter[i] == addr) {
return true;
}
}
return false;
}
if (client->filter_type == BLACKLIST) {
for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
if (client->filter[i] == addr) {
@ -927,6 +927,18 @@ static bool client_filter_match(struct bt_mesh_proxy_client *client,
return true;
}
if (addr == BT_MESH_ADDR_ALL_NODES) {
return true;
}
if (client->filter_type == WHITELIST) {
for (i = 0; i < ARRAY_SIZE(client->filter); i++) {
if (client->filter[i] == addr) {
return true;
}
}
}
return false;
}
@ -1146,7 +1158,7 @@ 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_ENABLED);
bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED);
}
static struct bt_mesh_subnet *next_sub(void)
@ -1189,7 +1201,7 @@ static s32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
BT_DBG("");
if (conn_count == CONFIG_BT_MAX_CONN) {
BT_WARN("Connectable advertising deferred (max connections)");
BT_DBG("Connectable advertising deferred (max connections)");
return remaining;
}
@ -1213,11 +1225,7 @@ static s32_t gatt_proxy_advertise(struct bt_mesh_subnet *sub)
}
if (sub->node_id == BT_MESH_NODE_IDENTITY_STOPPED) {
if (bt_mesh_gatt_proxy_get() == BT_MESH_GATT_PROXY_ENABLED) {
net_id_adv(sub);
} else {
return gatt_proxy_advertise(next_sub());
}
net_id_adv(sub);
}
subnet_count = sub_count();
@ -1353,12 +1361,39 @@ void bt_mesh_proxy_adv_stop(void)
}
}
int
ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg)
static void ble_mesh_handle_connect(struct ble_gap_event *event, void *arg)
{
#if MYNEWT_VAL(BLE_EXT_ADV)
/* When EXT ADV is enabled then mesh proxy is connected
* when proxy advertising instance is completed.
* Therefore no need to handle BLE_GAP_EVENT_CONNECT
*/
if (event->type == BLE_GAP_EVENT_ADV_COMPLETE) {
/* Reason 0 means advertising has been completed because
* connection has been established
*/
if (event->adv_complete.reason != 0) {
return;
}
if (event->adv_complete.instance != BT_MESH_ADV_GATT_INST) {
return;
}
proxy_connected(event->adv_complete.conn_handle);
}
#else
if (event->type == BLE_GAP_EVENT_CONNECT) {
proxy_connected(event->connect.conn_handle);
}
#endif
}
int ble_mesh_proxy_gap_event(struct ble_gap_event *event, void *arg)
{
if ((event->type == BLE_GAP_EVENT_CONNECT) ||
(event->type == BLE_GAP_EVENT_ADV_COMPLETE)) {
ble_mesh_handle_connect(event, arg);
} else if (event->type == BLE_GAP_EVENT_DISCONNECT) {
proxy_disconnected(event->disconnect.conn.conn_handle,
event->disconnect.reason);

View File

@ -19,7 +19,7 @@
int bt_mesh_proxy_send(uint16_t conn_handle, u8_t type, struct os_mbuf *msg);
int bt_mesh_proxy_prov_enable(void);
int bt_mesh_proxy_prov_disable(void);
int bt_mesh_proxy_prov_disable(bool disconnect);
int bt_mesh_proxy_gatt_enable(void);
int bt_mesh_proxy_gatt_disable(void);

View File

@ -5,11 +5,10 @@
*/
#include "syscfg/syscfg.h"
#define MESH_LOG_MODULE BLE_MESH_SETTINGS_LOG
#if MYNEWT_VAL(BLE_MESH_SETTINGS)
#define BT_DBG_ENABLED MYNEWT_VAL(BLE_MESH_DEBUG_SETTINGS)
#include "mesh/mesh.h"
#include "mesh/glue.h"
#include "net.h"
@ -19,6 +18,7 @@
#include "foundation.h"
#include "proxy.h"
#include "settings.h"
#include "nodes.h"
#include "config/config.h"
@ -105,6 +105,31 @@ struct mod_pub_val {
cred:1;
};
/* Virtual Address information */
struct va_val {
u16_t ref;
u16_t addr;
u8_t uuid[16];
} __packed;
/* Node storage information */
struct node_val {
u16_t net_idx;
u8_t dev_key[16];
u8_t num_elem;
} __packed;
struct node_update {
u16_t addr;
bool clear;
};
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
static struct node_update node_updates[CONFIG_BT_MESH_NODE_COUNT];
#else
static struct node_update node_updates[0];
#endif
/* We need this so we don't overwrite app-hardcoded values in case FCB
* contains a history of changes but then has a NULL at the end.
*/
@ -658,6 +683,14 @@ static int mod_set(bool vnd, int argc, char **argv, char *val)
return mod_set_pub(mod, val);
}
if (!strcmp(argv[1], "data")) {
mod->flags |= BT_MESH_MOD_DATA_PRESENT;
if (mod->cb && mod->cb->settings_set) {
return mod->cb->settings_set(mod, val);
}
}
BT_WARN("Unknown module key %s", argv[1]);
return -ENOENT;
}
@ -672,6 +705,115 @@ static int vnd_mod_set(int argc, char **argv, char *val)
return mod_set(true, argc, argv, val);
}
#if CONFIG_BT_MESH_LABEL_COUNT > 0
static int va_set(int argc, char **argv, char *val)
{
struct va_val va;
struct label *lab;
u16_t index;
int len, err;
if (argc < 1) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
index = strtol(argv[0], NULL, 16);
if (val == NULL) {
BT_WARN("Mesh Virtual Address length = 0");
return 0;
}
err = settings_bytes_from_str(val, &va, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return -EINVAL;
}
if (len != sizeof(struct va_val)) {
BT_ERR("Invalid length for virtual address");
return -EINVAL;
}
if (va.ref == 0) {
BT_WARN("Ignore Mesh Virtual Address ref = 0");
return 0;
}
lab = get_label(index);
if (lab == NULL) {
BT_WARN("Out of labels buffers");
return -ENOBUFS;
}
memcpy(lab->uuid, va.uuid, 16);
lab->addr = va.addr;
lab->ref = va.ref;
BT_DBG("Restored Virtual Address, addr 0x%04x ref 0x%04x",
lab->addr, lab->ref);
return 0;
}
#endif
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
static int node_set(int argc, char **argv, char *str)
{
struct bt_mesh_node *node;
struct node_val val;
u16_t addr;
int len, err;
if (argc < 1) {
BT_ERR("Insufficient number of arguments");
return -ENOENT;
}
addr = strtol(argv[0], NULL, 16);
if (str == NULL) {
BT_DBG("val (null)");
BT_DBG("Deleting node 0x%04x", addr);
node = bt_mesh_node_find(addr);
if (node) {
bt_mesh_node_del(node, false);
}
return 0;
}
err = settings_bytes_from_str(str, &val, &len);
if (err) {
BT_ERR("Failed to decode value %s (err %d)", val, err);
return -EINVAL;
}
if (len != sizeof(struct node_val)) {
BT_ERR("Invalid length for node_val");
return -EINVAL;
}
node = bt_mesh_node_find(addr);
if (!node) {
node = bt_mesh_node_alloc(addr, val.num_elem, val.net_idx);
}
if (!node) {
BT_ERR("No space for a new node");
return -ENOMEM;
}
memcpy(node->dev_key, &val.dev_key, 16);
BT_DBG("Node 0x%04x recovered from storage", addr);
return 0;
}
#endif
const struct mesh_setting {
const char *name;
int (*func)(int argc, char **argv, char *val);
@ -686,6 +828,12 @@ const struct mesh_setting {
{ "Cfg", cfg_set },
{ "s", sig_mod_set },
{ "v", vnd_mod_set },
#if CONFIG_BT_MESH_LABEL_COUNT > 0
{ "Va", va_set },
#endif
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
{ "Node", node_set },
#endif
};
static int mesh_set(int argc, char **argv, char *val)
@ -756,6 +904,10 @@ static void commit_mod(struct bt_mesh_model *mod, struct bt_mesh_elem *elem,
k_delayed_work_submit(&mod->pub->timer, ms);
}
}
if (mod->cb && mod->cb->settings_commit) {
mod->cb->settings_commit(mod);
}
}
static int mesh_commit(void)
@ -772,7 +924,7 @@ static int mesh_commit(void)
}
if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) {
bt_mesh_proxy_prov_disable();
bt_mesh_proxy_prov_disable(true);
}
for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
@ -820,24 +972,41 @@ static int mesh_commit(void)
return 0;
}
/* Pending flags that use K_NO_WAIT as the storage timeout */
#define NO_WAIT_PENDING_BITS (BIT(BT_MESH_NET_PENDING) | \
BIT(BT_MESH_IV_PENDING) | \
BIT(BT_MESH_SEQ_PENDING))
/* Pending flags that use CONFIG_BT_MESH_STORE_TIMEOUT */
#define GENERIC_PENDING_BITS (BIT(BT_MESH_KEYS_PENDING) | \
BIT(BT_MESH_HB_PUB_PENDING) | \
BIT(BT_MESH_CFG_PENDING) | \
BIT(BT_MESH_MOD_PENDING) | \
BIT(BT_MESH_NODES_PENDING))
static void schedule_store(int flag)
{
s32_t timeout;
s32_t timeout, remaining;
atomic_set_bit(bt_mesh.flags, flag);
if (atomic_test_bit(bt_mesh.flags, BT_MESH_NET_PENDING) ||
atomic_test_bit(bt_mesh.flags, BT_MESH_IV_PENDING) ||
atomic_test_bit(bt_mesh.flags, BT_MESH_SEQ_PENDING)) {
if (atomic_get(bt_mesh.flags) & NO_WAIT_PENDING_BITS) {
timeout = K_NO_WAIT;
} else if (atomic_test_bit(bt_mesh.flags, BT_MESH_RPL_PENDING) &&
(CONFIG_BT_MESH_RPL_STORE_TIMEOUT <
CONFIG_BT_MESH_STORE_TIMEOUT)) {
(!(atomic_get(bt_mesh.flags) & GENERIC_PENDING_BITS) ||
(CONFIG_BT_MESH_RPL_STORE_TIMEOUT <
CONFIG_BT_MESH_STORE_TIMEOUT))) {
timeout = K_SECONDS(CONFIG_BT_MESH_RPL_STORE_TIMEOUT);
} else {
timeout = K_SECONDS(CONFIG_BT_MESH_STORE_TIMEOUT);
}
remaining = k_delayed_work_remaining_get(&pending_store);
if (remaining && remaining < timeout) {
BT_DBG("Not rescheduling due to existing earlier deadline");
return;
}
BT_DBG("Waiting %d seconds", (int) (timeout / MSEC_PER_SEC));
k_delayed_work_submit(&pending_store, timeout);
@ -845,14 +1014,26 @@ static void schedule_store(int flag)
static void clear_iv(void)
{
BT_DBG("Clearing IV");
settings_save_one("bt_mesh/IV", NULL);
int err;
err = settings_save_one("bt_mesh/IV", NULL);
if (err) {
BT_ERR("Failed to clear IV");
} else {
BT_DBG("Cleared IV");
}
}
static void clear_net(void)
{
BT_DBG("Clearing Network");
settings_save_one("bt_mesh/Net", NULL);
int err;
err = settings_save_one("bt_mesh/Net", NULL);
if (err) {
BT_ERR("Failed to clear Network");
} else {
BT_DBG("Cleared Network");
}
}
static void store_pending_net(void)
@ -860,6 +1041,7 @@ static void store_pending_net(void)
char buf[BT_SETTINGS_SIZE(sizeof(struct net_val))];
struct net_val net;
char *str;
int err;
BT_DBG("addr 0x%04x DevKey %s", bt_mesh_primary_addr(),
bt_hex(bt_mesh.dev_key, 16));
@ -874,7 +1056,12 @@ static void store_pending_net(void)
}
BT_DBG("Saving Network as value %s", str);
settings_save_one("bt_mesh/Net", str);
err = settings_save_one("bt_mesh/Net", str);
if (err) {
BT_ERR("Failed to store Network");
} else {
BT_DBG("Stored Network");
}
}
void bt_mesh_store_net(void)
@ -887,6 +1074,7 @@ static void store_pending_iv(void)
char buf[BT_SETTINGS_SIZE(sizeof(struct iv_val))];
struct iv_val iv;
char *str;
int err;
iv.iv_index = bt_mesh.iv_index;
iv.iv_update = atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
@ -899,7 +1087,12 @@ static void store_pending_iv(void)
}
BT_DBG("Saving IV as value %s", str);
settings_save_one("bt_mesh/IV", str);
err = settings_save_one("bt_mesh/IV", str);
if (err) {
BT_ERR("Failed to store IV");
} else {
BT_DBG("Stored IV");
}
}
void bt_mesh_store_iv(bool only_duration)
@ -917,6 +1110,7 @@ static void store_pending_seq(void)
char buf[BT_SETTINGS_SIZE(sizeof(struct seq_val))];
struct seq_val seq;
char *str;
int err;
seq.val[0] = bt_mesh.seq;
seq.val[1] = bt_mesh.seq >> 8;
@ -929,7 +1123,12 @@ static void store_pending_seq(void)
}
BT_DBG("Saving Seq as value %s", str);
settings_save_one("bt_mesh/Seq", str);
err = settings_save_one("bt_mesh/Seq", str);
if (err) {
BT_ERR("Failed to store Seq");
} else {
BT_DBG("Stored Seq");
}
}
void bt_mesh_store_seq(void)
@ -948,6 +1147,7 @@ static void store_rpl(struct bt_mesh_rpl *entry)
struct rpl_val rpl;
char path[18];
char *str;
int err;
BT_DBG("src 0x%04x seq 0x%06x old_iv %u", entry->src,
(unsigned) entry->seq, entry->old_iv);
@ -964,12 +1164,17 @@ static void store_rpl(struct bt_mesh_rpl *entry)
snprintk(path, sizeof(path), "bt_mesh/RPL/%x", entry->src);
BT_DBG("Saving RPL %s as value %s", path, str);
settings_save_one(path, str);
err = settings_save_one(path, str);
if (err) {
BT_ERR("Failed to store RPL");
} else {
BT_DBG("Stored RPL");
}
}
static void clear_rpl(void)
{
int i;
int i, err;
BT_DBG("");
@ -982,7 +1187,12 @@ static void clear_rpl(void)
}
snprintk(path, sizeof(path), "bt_mesh/RPL/%x", rpl->src);
settings_save_one(path, NULL);
err = settings_save_one(path, NULL);
if (err) {
BT_ERR("Failed to clear RPL");
} else {
BT_DBG("Cleared RPL");
}
memset(rpl, 0, sizeof(*rpl));
}
@ -1010,6 +1220,7 @@ static void store_pending_hb_pub(void)
struct bt_mesh_hb_pub *pub = bt_mesh_hb_pub_get();
struct hb_pub_val val;
char *str;
int err;
if (!pub) {
return;
@ -1035,7 +1246,12 @@ static void store_pending_hb_pub(void)
BT_DBG("Saving Heartbeat Publication as value %s",
str ? str : "(null)");
settings_save_one("bt_mesh/HBPub", str);
err = settings_save_one("bt_mesh/HBPub", str);
if (err) {
BT_ERR("Failed to store Heartbeat Publication");
} else {
BT_DBG("Stored Heartbeat Publication");
}
}
static void store_pending_cfg(void)
@ -1044,6 +1260,7 @@ static void store_pending_cfg(void)
struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get();
struct cfg_val val;
char *str;
int err;
if (!cfg) {
return;
@ -1064,33 +1281,56 @@ static void store_pending_cfg(void)
}
BT_DBG("Saving configuration as value %s", str);
settings_save_one("bt_mesh/Cfg", str);
err = settings_save_one("bt_mesh/Cfg", str);
if (err) {
BT_ERR("Failed to store configuration");
} else {
BT_DBG("Stored configuration");
}
}
static void clear_cfg(void)
{
BT_DBG("Clearing configuration");
settings_save_one("bt_mesh/Cfg", NULL);
int err;
err = settings_save_one("bt_mesh/Cfg", NULL);
if (err) {
BT_ERR("Failed to clear configuration");
} else {
BT_DBG("Cleared configuration");
}
}
static void clear_app_key(u16_t app_idx)
{
char path[20];
int err;
BT_DBG("AppKeyIndex 0x%03x", app_idx);
snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app_idx);
settings_save_one(path, NULL);
err = settings_save_one(path, NULL);
if (err) {
BT_ERR("Failed to clear AppKeyIndex 0x%03x", app_idx);
} else {
BT_DBG("Cleared AppKeyIndex 0x%03x", app_idx);
}
}
static void clear_net_key(u16_t net_idx)
{
char path[20];
int err;
BT_DBG("NetKeyIndex 0x%03x", net_idx);
snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", net_idx);
settings_save_one(path, NULL);
err = settings_save_one(path, NULL);
if (err) {
BT_ERR("Failed to clear NetKeyIndex 0x%03x", net_idx);
} else {
BT_DBG("Cleared NetKeyIndex 0x%03x", net_idx);
}
}
static void store_net_key(struct bt_mesh_subnet *sub)
@ -1099,6 +1339,7 @@ static void store_net_key(struct bt_mesh_subnet *sub)
struct net_key_val key;
char path[20];
char *str;
int err;
BT_DBG("NetKeyIndex 0x%03x NetKey %s", sub->net_idx,
bt_hex(sub->keys[0].net, 16));
@ -1117,7 +1358,12 @@ static void store_net_key(struct bt_mesh_subnet *sub)
snprintk(path, sizeof(path), "bt_mesh/NetKey/%x", sub->net_idx);
BT_DBG("Saving NetKey %s as value %s", path, str);
settings_save_one(path, str);
err = settings_save_one(path, str);
if (err) {
BT_ERR("Failed to store NetKey");
} else {
BT_DBG("Stored NetKey");
}
}
static void store_app_key(struct bt_mesh_app_key *app)
@ -1126,6 +1372,7 @@ static void store_app_key(struct bt_mesh_app_key *app)
struct app_key_val key;
char path[20];
char *str;
int err;
key.net_idx = app->net_idx;
key.updated = app->updated;
@ -1141,7 +1388,12 @@ static void store_app_key(struct bt_mesh_app_key *app)
snprintk(path, sizeof(path), "bt_mesh/AppKey/%x", app->app_idx);
BT_DBG("Saving AppKey %s as value %s", path, str);
settings_save_one(path, str);
err = settings_save_one(path, str);
if (err) {
BT_ERR("Failed to store AppKey");
} else {
BT_DBG("Stored AppKey");
}
}
static void store_pending_keys(void)
@ -1190,6 +1442,104 @@ static void store_pending_keys(void)
}
}
static void store_node(struct bt_mesh_node *node)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct node_val))];
struct node_val val;
char path[20];
char *str;
int err;
val.net_idx = node->net_idx;
val.num_elem = node->num_elem;
memcpy(val.dev_key, node->dev_key, 16);
snprintk(path, sizeof(path), "bt_mesh/Node/%x", node->addr);
str = settings_str_from_bytes(&val, sizeof(val), buf, sizeof(buf));
if (!str) {
BT_ERR("Unable to encode Node as value");
return;
}
err = settings_save_one(path, str);
if (err) {
BT_ERR("Failed to store Node %s value", path);
} else {
BT_DBG("Stored Node %s value", path);
}
}
static void clear_node(u16_t addr)
{
char path[20];
int err;
BT_DBG("Node 0x%04x", addr);
snprintk(path, sizeof(path), "bt_mesh/Node/%x", addr);
err = settings_save_one(path, NULL);
if (err) {
BT_ERR("Failed to clear Node 0x%04x", addr);
} else {
BT_DBG("Cleared Node 0x%04x", addr);
}
}
static void store_pending_nodes(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(node_updates); ++i) {
struct node_update *update = &node_updates[i];
if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
continue;
}
if (update->clear) {
clear_node(update->addr);
} else {
struct bt_mesh_node *node;
node = bt_mesh_node_find(update->addr);
if (node) {
store_node(node);
} else {
BT_WARN("Node 0x%04x not found", update->addr);
}
}
update->addr = BT_MESH_ADDR_UNASSIGNED;
}
}
static struct node_update *node_update_find(u16_t addr,
struct node_update **free_slot)
{
struct node_update *match;
int i;
match = NULL;
*free_slot = NULL;
for (i = 0; i < ARRAY_SIZE(node_updates); i++) {
struct node_update *update = &node_updates[i];
if (update->addr == BT_MESH_ADDR_UNASSIGNED) {
*free_slot = update;
continue;
}
if (update->addr == addr) {
match = update;
}
}
return match;
}
static void encode_mod_path(struct bt_mesh_model *mod, bool vnd,
const char *key, char *path, size_t path_len)
{
@ -1207,7 +1557,7 @@ static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd)
u16_t keys[CONFIG_BT_MESH_MODEL_KEY_COUNT];
char buf[BT_SETTINGS_SIZE(sizeof(keys))];
char path[20];
int i, count;
int i, count, err;
char *val;
for (i = 0, count = 0; i < ARRAY_SIZE(mod->keys); i++) {
@ -1230,7 +1580,12 @@ static void store_pending_mod_bind(struct bt_mesh_model *mod, bool vnd)
encode_mod_path(mod, vnd, "bind", path, sizeof(path));
BT_DBG("Saving %s as %s", path, val ? val : "(null)");
settings_save_one(path, val);
err = settings_save_one(path, val);
if (err) {
BT_ERR("Failed to store bind");
} else {
BT_DBG("Stored bind");
}
}
static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd)
@ -1238,10 +1593,10 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd)
u16_t groups[CONFIG_BT_MESH_MODEL_GROUP_COUNT];
char buf[BT_SETTINGS_SIZE(sizeof(groups))];
char path[20];
int i, count;
int i, count, err;
char *val;
for (i = 0, count = 0; i < ARRAY_SIZE(mod->groups); i++) {
for (i = 0, count = 0; i < CONFIG_BT_MESH_MODEL_GROUP_COUNT; i++) {
if (mod->groups[i] != BT_MESH_ADDR_UNASSIGNED) {
groups[count++] = mod->groups[i];
}
@ -1261,7 +1616,12 @@ static void store_pending_mod_sub(struct bt_mesh_model *mod, bool vnd)
encode_mod_path(mod, vnd, "sub", path, sizeof(path));
BT_DBG("Saving %s as %s", path, val ? val : "(null)");
settings_save_one(path, val);
err = settings_save_one(path, val);
if (err) {
BT_ERR("Failed to store sub");
} else {
BT_DBG("Stored sub");
}
}
static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
@ -1270,6 +1630,7 @@ static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
struct mod_pub_val pub;
char path[20];
char *val;
int err;
if (!mod->pub || mod->pub->addr == BT_MESH_ADDR_UNASSIGNED) {
val = NULL;
@ -1293,7 +1654,12 @@ static void store_pending_mod_pub(struct bt_mesh_model *mod, bool vnd)
encode_mod_path(mod, vnd, "pub", path, sizeof(path));
BT_DBG("Saving %s as %s", path, val ? val : "(null)");
settings_save_one(path, val);
err = settings_save_one(path, val);
if (err) {
BT_ERR("Failed to store pub");
} else {
BT_DBG("Stored pub");
}
}
static void store_pending_mod(struct bt_mesh_model *mod,
@ -1320,6 +1686,52 @@ static void store_pending_mod(struct bt_mesh_model *mod,
}
}
#define IS_VA_DEL(_label) ((_label)->ref == 0)
static void store_pending_va(void)
{
char buf[BT_SETTINGS_SIZE(sizeof(struct va_val))];
struct label *lab;
struct va_val va;
char path[18];
char *val;
u16_t i;
int err = 0;
for (i = 0; (lab = get_label(i)) != NULL; i++) {
if (!atomic_test_and_clear_bit(lab->flags,
BT_MESH_VA_CHANGED)) {
continue;
}
snprintk(path, sizeof(path), "bt_mesh/Va/%x", i);
if (IS_VA_DEL(lab)) {
val = NULL;
} else {
va.ref = lab->ref;
va.addr = lab->addr;
memcpy(va.uuid, lab->uuid, 16);
val = settings_str_from_bytes(&va, sizeof(va),
buf, sizeof(buf));
if (!val) {
BT_ERR("Unable to encode model publication as value");
return;
}
err = settings_save_one(path, val);
}
if (err) {
BT_ERR("Failed to %s %s value (err %d)",
IS_VA_DEL(lab) ? "delete" : "store", path, err);
} else {
BT_DBG("%s %s value",
IS_VA_DEL(lab) ? "Deleted" : "Stored", path);
}
}
}
static void store_pending(struct ble_npl_event *work)
{
BT_DBG("");
@ -1371,6 +1783,15 @@ static void store_pending(struct ble_npl_event *work)
if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_MOD_PENDING)) {
bt_mesh_model_foreach(store_pending_mod, NULL);
}
if (atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_VA_PENDING)) {
store_pending_va();
}
if (IS_ENABLED(CONFIG_BT_MESH_PROVISIONER) &&
atomic_test_and_clear_bit(bt_mesh.flags, BT_MESH_NODES_PENDING)) {
store_pending_nodes();
}
}
void bt_mesh_store_rpl(struct bt_mesh_rpl *entry)
@ -1552,6 +1973,93 @@ void bt_mesh_store_mod_pub(struct bt_mesh_model *mod)
schedule_store(BT_MESH_MOD_PENDING);
}
void bt_mesh_store_label(void)
{
schedule_store(BT_MESH_VA_PENDING);
}
void bt_mesh_store_node(struct bt_mesh_node *node)
{
struct node_update *update, *free_slot;
BT_DBG("Node 0x%04x", node->addr);
update = node_update_find(node->addr, &free_slot);
if (update) {
update->clear = false;
schedule_store(BT_MESH_NODES_PENDING);
return;
}
if (!free_slot) {
store_node(node);
return;
}
free_slot->addr = node->addr;
schedule_store(BT_MESH_NODES_PENDING);
}
void bt_mesh_clear_node(struct bt_mesh_node *node)
{
struct node_update *update, *free_slot;
BT_DBG("Node 0x%04x", node->addr);
update = node_update_find(node->addr, &free_slot);
if (update) {
update->clear = true;
schedule_store(BT_MESH_NODES_PENDING);
return;
}
if (!free_slot) {
clear_node(node->addr);
return;
}
free_slot->addr = node->addr;
schedule_store(BT_MESH_NODES_PENDING);
}
int bt_mesh_model_data_store(struct bt_mesh_model *mod, bool vnd,
const void *data, size_t data_len)
{
char path[20];
char buf[BT_SETTINGS_SIZE(sizeof(struct mod_pub_val))];
char *val;
int err;
encode_mod_path(mod, vnd, "data", path, sizeof(path));
if (data_len) {
mod->flags |= BT_MESH_MOD_DATA_PRESENT;
val = settings_str_from_bytes(data, data_len,
buf, sizeof(buf));
if (!val) {
BT_ERR("Unable to encode model publication as value");
return -EINVAL;
}
err = settings_save_one(path, val);
} else if (mod->flags & BT_MESH_MOD_DATA_PRESENT) {
mod->flags &= ~BT_MESH_MOD_DATA_PRESENT;
err = settings_save_one(path, NULL);
} else {
/* Nothing to delete */
err = 0;
}
if (err) {
BT_ERR("Failed to store %s value", path);
} else {
BT_DBG("Stored %s value", path);
}
return err;
}
static struct conf_handler bt_mesh_settings_conf_handler = {
.ch_name = "bt_mesh",
.ch_get = NULL,

View File

@ -15,10 +15,13 @@ 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_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_rpl(void);
void bt_mesh_clear_node(struct bt_mesh_node *node);
void bt_mesh_settings_init(void);

View File

@ -222,37 +222,46 @@ static struct bt_mesh_health_cli health_cli = {
#endif /* MYNEWT_VAL(BLE_MESH_HEALTH_CLI) */
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
static struct bt_mesh_model_pub gen_onoff_pub;
static struct bt_mesh_model_pub gen_level_pub;
static struct bt_mesh_gen_model_cli gen_onoff_cli;
static struct bt_mesh_model_pub gen_onoff_cli_pub;
static struct bt_mesh_model_pub gen_onoff_srv_pub;
static struct bt_mesh_gen_model_cli gen_level_cli;
static struct bt_mesh_model_pub gen_level_cli_pub;
static struct bt_mesh_model_pub gen_level_srv_pub;
static struct bt_mesh_model_pub light_lightness_pub;
static struct bt_mesh_gen_onoff_srv_cb gen_onoff_srv_cb = {
static struct bt_mesh_gen_onoff_srv gen_onoff_srv = {
.get = light_model_gen_onoff_get,
.set = light_model_gen_onoff_set,
};
static struct bt_mesh_gen_level_srv_cb gen_level_srv_cb = {
static struct bt_mesh_gen_level_srv gen_level_srv = {
.get = light_model_gen_level_get,
.set = light_model_gen_level_set,
};
static struct bt_mesh_light_lightness_srv_cb light_lightness_srv_cb = {
static struct bt_mesh_light_lightness_srv light_lightness_srv = {
.get = light_model_light_lightness_get,
.set = light_model_light_lightness_set,
};
void bt_mesh_set_gen_onoff_srv_cb(struct bt_mesh_gen_onoff_srv_cb *gen_onoff_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))
{
gen_onoff_srv_cb = *gen_onoff_cb;
gen_onoff_srv.get = get;
gen_onoff_srv.set = set;
}
void bt_mesh_set_gen_level_srv_cb(struct bt_mesh_gen_level_srv_cb *gen_level_cb)
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))
{
gen_level_srv_cb = *gen_level_cb;
gen_level_srv.get = get;
gen_level_srv.set = set;
}
void bt_mesh_set_light_lightness_srv_cb(struct bt_mesh_light_lightness_srv_cb *light_lightness_cb)
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))
{
light_lightness_srv_cb = *light_lightness_cb;
light_lightness_srv.get = get;
light_lightness_srv.set = set;
}
#endif
static struct bt_mesh_model root_models[] = {
@ -265,11 +274,11 @@ static struct bt_mesh_model root_models[] = {
BT_MESH_MODEL_HEALTH_CLI(&health_cli),
#endif
#if MYNEWT_VAL(BLE_MESH_SHELL_MODELS)
BT_MESH_MODEL_GEN_ONOFF_SRV(&gen_onoff_srv_cb, &gen_onoff_pub),
BT_MESH_MODEL_GEN_ONOFF_CLI(),
BT_MESH_MODEL_GEN_LEVEL_SRV(&gen_level_srv_cb, &gen_level_pub),
BT_MESH_MODEL_GEN_LEVEL_CLI(),
BT_MESH_MODEL_LIGHT_LIGHTNESS_SRV(&light_lightness_srv_cb, &light_lightness_pub),
BT_MESH_MODEL_GEN_ONOFF_SRV(&gen_onoff_srv, &gen_onoff_srv_pub),
BT_MESH_MODEL_GEN_ONOFF_CLI(&gen_onoff_cli, &gen_onoff_cli_pub),
BT_MESH_MODEL_GEN_LEVEL_SRV(&gen_level_srv, &gen_level_srv_pub),
BT_MESH_MODEL_GEN_LEVEL_CLI(&gen_level_cli, &gen_level_cli_pub),
BT_MESH_MODEL_LIGHT_LIGHTNESS_SRV(&light_lightness_srv, &light_lightness_pub),
#endif
};
@ -323,11 +332,25 @@ static void prov_complete(u16_t net_idx, u16_t addr)
{
printk("Local node provisioned, net_idx 0x%04x address 0x%04x\n",
net_idx, addr);
net.net_idx = net_idx,
net.local = addr;
net.net_idx = net_idx,
net.dst = addr;
}
static void prov_node_added(u16_t net_idx, u16_t addr, u8_t num_elem)
{
printk("Node provisioned, net_idx 0x%04x address "
"0x%04x elements %d", net_idx, addr, num_elem);
net.net_idx = net_idx,
net.dst = addr;
}
static void prov_input_complete(void)
{
printk("Input complete");
}
static void prov_reset(void)
{
printk("The local node has been reset and needs reprovisioning\n");
@ -467,6 +490,7 @@ static struct bt_mesh_prov prov = {
.link_open = link_open,
.link_close = link_close,
.complete = prov_complete,
.node_added = prov_node_added,
.reset = prov_reset,
.static_val = NULL,
.static_val_len = 0,
@ -477,6 +501,7 @@ static struct bt_mesh_prov prov = {
.input_size = MYNEWT_VAL(BLE_MESH_OOB_INPUT_SIZE),
.input_actions = MYNEWT_VAL(BLE_MESH_OOB_INPUT_ACTIONS),
.input = input,
.input_complete = prov_input_complete,
};
static int cmd_static_oob(int argc, char *argv[])
@ -794,19 +819,6 @@ struct shell_cmd_help cmd_net_send_help = {
NULL, "<hex string>", NULL
};
static int cmd_iv_update(int argc, char *argv[])
{
if (bt_mesh_iv_update()) {
printk("Transitioned to IV Update In Progress state\n");
} else {
printk("Transitioned to IV Update Normal state\n");
}
printk("IV Index is 0x%08lx\n", bt_mesh.iv_index);
return 0;
}
static int cmd_rpl_clear(int argc, char *argv[])
{
bt_mesh_rpl_clear();
@ -857,6 +869,20 @@ struct shell_cmd_help cmd_lpn_unsubscribe_help = {
};
#endif
#if MYNEWT_VAL(BLE_MESH_IV_UPDATE_TEST)
static int cmd_iv_update(int argc, char *argv[])
{
if (bt_mesh_iv_update()) {
printk("Transitioned to IV Update In Progress state\n");
} else {
printk("Transitioned to IV Update Normal state\n");
}
printk("IV Index is 0x%08lx\n", bt_mesh.iv_index);
return 0;
}
static int cmd_iv_update_test(int argc, char *argv[])
{
bool enable;
@ -880,6 +906,7 @@ static int cmd_iv_update_test(int argc, char *argv[])
struct shell_cmd_help cmd_iv_update_test_help = {
NULL, "<value: off, on>", NULL
};
#endif
#if MYNEWT_VAL(BLE_MESH_CFG_CLI)
@ -1802,6 +1829,37 @@ static int cmd_pb_adv(int argc, char *argv[])
{
return cmd_pb(BT_MESH_PROV_ADV, argc, argv);
}
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
static int cmd_provision_adv(int argc, char *argv[])
{
u8_t uuid[16];
u8_t attention_duration;
u16_t net_idx;
u16_t addr;
size_t len;
int err;
len = hex2bin(argv[1], uuid, sizeof(uuid));
(void)memset(uuid + len, 0, sizeof(uuid) - len);
net_idx = strtoul(argv[2], NULL, 0);
addr = strtoul(argv[3], NULL, 0);
attention_duration = strtoul(argv[4], NULL, 0);
err = bt_mesh_provision_adv(uuid, net_idx, addr, attention_duration);
if (err) {
printk("Provisioning failed (err %d)", err);
}
return 0;
}
struct shell_cmd_help cmd_provision_adv_help = {
NULL, "<UUID> <NetKeyIndex> <addr> <AttentionDuration>" , NULL
};
#endif /* CONFIG_BT_MESH_PROVISIONER */
#endif /* CONFIG_BT_MESH_PB_ADV */
#if MYNEWT_VAL(BLE_MESH_PB_GATT)
@ -2403,6 +2461,13 @@ static const struct shell_cmd mesh_commands[] = {
.sc_cmd_func = cmd_pb_adv,
.help = &cmd_pb_help,
},
#if MYNEWT_VAL(BLE_MESH_PROVISIONER)
{
.sc_cmd = "provision-adv",
.sc_cmd_func = cmd_provision_adv,
.help = &cmd_provision_adv_help,
},
#endif
#endif
#if MYNEWT_VAL(BLE_MESH_PB_GATT)
{
@ -2482,6 +2547,7 @@ static const struct shell_cmd mesh_commands[] = {
.sc_cmd_func = cmd_net_send,
.help = &cmd_net_send_help,
},
#if MYNEWT_VAL(BLE_MESH_IV_UPDATE_TEST)
{
.sc_cmd = "iv-update",
.sc_cmd_func = cmd_iv_update,
@ -2492,6 +2558,7 @@ static const struct shell_cmd mesh_commands[] = {
.sc_cmd_func = cmd_iv_update_test,
.help = &cmd_iv_update_test_help,
},
#endif
{
.sc_cmd = "rpl-clear",
.sc_cmd_func = cmd_rpl_clear,

View File

@ -357,7 +357,6 @@ void ble_att_error_rsp_parse(const void *payload, int len,
struct ble_att_error_rsp *rsp);
void ble_att_error_rsp_write(void *payload, int len,
const struct ble_att_error_rsp *rsp);
void ble_att_error_rsp_log(const struct ble_att_error_rsp *cmd);
void ble_att_mtu_req_parse(const void *payload, int len,
struct ble_att_mtu_cmd *cmd);
void ble_att_mtu_req_write(void *payload, int len,
@ -366,43 +365,34 @@ void ble_att_mtu_rsp_parse(const void *payload, int len,
struct ble_att_mtu_cmd *cmd);
void ble_att_mtu_rsp_write(void *payload, int len,
const struct ble_att_mtu_cmd *cmd);
void ble_att_mtu_cmd_log(const struct ble_att_mtu_cmd *cmd);
void ble_att_find_info_req_parse(const void *payload, int len,
struct ble_att_find_info_req *req);
void ble_att_find_info_req_write(void *payload, int len,
const struct ble_att_find_info_req *req);
void ble_att_find_info_req_log(const struct ble_att_find_info_req *cmd);
void ble_att_find_info_rsp_parse(const void *payload, int len,
struct ble_att_find_info_rsp *rsp);
void ble_att_find_info_rsp_write(void *payload, int len,
const struct ble_att_find_info_rsp *rsp);
void ble_att_find_info_rsp_log(const struct ble_att_find_info_rsp *cmd);
void ble_att_find_type_value_req_parse(
const void *payload, int len, struct ble_att_find_type_value_req *req);
void ble_att_find_type_value_req_write(
void *payload, int len, const struct ble_att_find_type_value_req *req);
void ble_att_find_type_value_req_log(
const struct ble_att_find_type_value_req *cmd);
void ble_att_read_type_req_parse(const void *payload, int len,
struct ble_att_read_type_req *req);
void ble_att_read_type_req_write(void *payload, int len,
const struct ble_att_read_type_req *req);
void ble_att_read_type_req_log(const struct ble_att_read_type_req *cmd);
void ble_att_read_type_rsp_parse(const void *payload, int len,
struct ble_att_read_type_rsp *rsp);
void ble_att_read_type_rsp_write(void *payload, int len,
const struct ble_att_read_type_rsp *rsp);
void ble_att_read_type_rsp_log(const struct ble_att_read_type_rsp *cmd);
void ble_att_read_req_parse(const void *payload, int len,
struct ble_att_read_req *req);
void ble_att_read_req_write(void *payload, int len,
const struct ble_att_read_req *req);
void ble_att_read_req_log(const struct ble_att_read_req *cmd);
void ble_att_read_blob_req_parse(const void *payload, int len,
struct ble_att_read_blob_req *req);
void ble_att_read_blob_req_write(void *payload, int len,
const struct ble_att_read_blob_req *req);
void ble_att_read_blob_req_log(const struct ble_att_read_blob_req *cmd);
void ble_att_read_mult_req_parse(const void *payload, int len);
void ble_att_read_mult_req_write(void *payload, int len);
void ble_att_read_mult_rsp_parse(const void *payload, int len);
@ -411,14 +401,10 @@ void ble_att_read_group_type_req_parse(
const void *payload, int len, struct ble_att_read_group_type_req *req);
void ble_att_read_group_type_req_write(
void *payload, int len, const struct ble_att_read_group_type_req *req);
void ble_att_read_group_type_req_log(
const struct ble_att_read_group_type_req *cmd);
void ble_att_read_group_type_rsp_parse(
const void *payload, int len, struct ble_att_read_group_type_rsp *rsp);
void ble_att_read_group_type_rsp_write(
void *payload, int len, const struct ble_att_read_group_type_rsp *rsp);
void ble_att_read_group_type_rsp_log(
const struct ble_att_read_group_type_rsp *cmd);
void ble_att_write_req_parse(const void *payload, int len,
struct ble_att_write_req *req);
void ble_att_write_req_write(void *payload, int len,
@ -427,20 +413,16 @@ void ble_att_write_cmd_parse(const void *payload, int len,
struct ble_att_write_req *req);
void ble_att_write_cmd_write(void *payload, int len,
const struct ble_att_write_req *req);
void ble_att_write_cmd_log(const struct ble_att_write_cmd *cmd);
void ble_att_write_req_log(const struct ble_att_write_req *req);
void ble_att_prep_write_req_parse(const void *payload, int len,
struct ble_att_prep_write_cmd *cmd);
void ble_att_prep_write_req_write(void *payload, int len,
const struct ble_att_prep_write_cmd *cmd);
void ble_att_prep_write_cmd_log(const struct ble_att_prep_write_cmd *cmd);
void ble_att_prep_write_rsp_parse(const void *payload, int len,
struct ble_att_prep_write_cmd *cmd);
void ble_att_prep_write_rsp_write(void *payload, int len,
const struct ble_att_prep_write_cmd *cmd);
void ble_att_exec_write_req_parse(const void *payload, int len,
struct ble_att_exec_write_req *req);
void ble_att_exec_write_req_log(const struct ble_att_exec_write_req *cmd);
void ble_att_exec_write_req_write(void *payload, int len,
const struct ble_att_exec_write_req *req);
void ble_att_exec_write_rsp_parse(const void *payload, int len);
@ -449,14 +431,12 @@ void ble_att_notify_req_parse(const void *payload, int len,
struct ble_att_notify_req *req);
void ble_att_notify_req_write(void *payload, int len,
const struct ble_att_notify_req *req);
void ble_att_notify_req_log(const struct ble_att_notify_req *cmd);
void ble_att_indicate_req_parse(const void *payload, int len,
struct ble_att_indicate_req *req);
void ble_att_indicate_req_write(void *payload, int len,
const struct ble_att_indicate_req *req);
void ble_att_indicate_rsp_parse(const void *payload, int len);
void ble_att_indicate_rsp_write(void *payload, int len);
void ble_att_indicate_req_log(const struct ble_att_indicate_req *cmd);
void *ble_att_cmd_prepare(uint8_t opcode, size_t len, struct os_mbuf *txom);
void *ble_att_cmd_get(uint8_t opcode, size_t len, struct os_mbuf **txom);

View File

@ -170,12 +170,6 @@ void ble_att_set_peer_mtu(struct ble_l2cap_chan *chan, uint16_t peer_mtu);
uint16_t ble_att_chan_mtu(const struct ble_l2cap_chan *chan);
int ble_att_init(void);
#define BLE_ATT_LOG_CMD(is_tx, cmd_name, conn_handle, log_cb, cmd) \
BLE_HS_LOG_CMD((is_tx), "att", (cmd_name), (conn_handle), (log_cb), (cmd))
#define BLE_ATT_LOG_EMPTY_CMD(is_tx, cmd_name, conn_handle) \
BLE_HS_LOG_EMPTY_CMD((is_tx), "att", (cmd_name), (conn_handle))
/*** @svr */
int ble_att_svr_start(void);

View File

@ -81,23 +81,40 @@ void ble_gap_rx_le_scan_timeout(void);
#if MYNEWT_VAL(BLE_EXT_ADV)
void ble_gap_rx_ext_adv_report(struct ble_gap_ext_disc_desc *desc);
void ble_gap_rx_adv_set_terminated(struct hci_le_adv_set_terminated *evt);
void ble_gap_rx_adv_set_terminated(const struct ble_hci_ev_le_subev_adv_set_terminated *ev);
#if MYNEWT_VAL(BLE_PERIODIC_ADV)
void ble_gap_rx_peroidic_adv_sync_estab(struct hci_le_subev_periodic_adv_sync_estab *evt);
void ble_gap_rx_periodic_adv_rpt(struct hci_le_subev_periodic_adv_rpt *evt);
void ble_gap_rx_periodic_adv_sync_lost(struct hci_le_subev_periodic_adv_sync_lost *evt);
void ble_gap_rx_peroidic_adv_sync_estab(const struct ble_hci_ev_le_subev_periodic_adv_sync_estab *ev);
void ble_gap_rx_periodic_adv_rpt(const struct ble_hci_ev_le_subev_periodic_adv_rpt *ev);
void ble_gap_rx_periodic_adv_sync_lost(const struct ble_hci_ev_le_subev_periodic_adv_sync_lost *ev);
void ble_gap_rx_periodic_adv_sync_transfer(const struct ble_hci_ev_le_subev_periodic_adv_sync_transfer *ev);
#endif
void ble_gap_rx_scan_req_rcvd(struct hci_le_scan_req_rcvd *evt);
void ble_gap_rx_scan_req_rcvd(const struct ble_hci_ev_le_subev_scan_req_rcvd *ev);
#endif
void ble_gap_rx_adv_report(struct ble_gap_disc_desc *desc);
void ble_gap_rx_rd_rem_sup_feat_complete(struct hci_le_rd_rem_supp_feat_complete *evt);
int ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt, uint8_t instance);
void ble_gap_rx_disconn_complete(struct hci_disconn_complete *evt);
void ble_gap_rx_update_complete(struct hci_le_conn_upd_complete *evt);
void ble_gap_rx_param_req(struct hci_le_conn_param_req *evt);
void ble_gap_rx_rd_rem_sup_feat_complete(const struct ble_hci_ev_le_subev_rd_rem_used_feat *ev);
struct ble_gap_conn_complete
{
uint8_t status;
uint16_t connection_handle;
uint8_t role;
uint8_t peer_addr_type;
uint8_t peer_addr[BLE_DEV_ADDR_LEN];
uint16_t conn_itvl;
uint16_t conn_latency;
uint16_t supervision_timeout;
uint8_t master_clk_acc;
uint8_t local_rpa[BLE_DEV_ADDR_LEN];
uint8_t peer_rpa[BLE_DEV_ADDR_LEN];
};
int ble_gap_rx_conn_complete(struct ble_gap_conn_complete *evt, uint8_t instance);
void ble_gap_rx_disconn_complete(const struct ble_hci_ev_disconn_cmp *ev);
void ble_gap_rx_update_complete(const struct ble_hci_ev_le_subev_conn_upd_complete *ev);
void ble_gap_rx_param_req(const struct ble_hci_ev_le_subev_rem_conn_param_req *ev);
int ble_gap_rx_l2cap_update_req(uint16_t conn_handle,
struct ble_gap_upd_params *params);
void ble_gap_rx_phy_update_complete(struct hci_le_phy_upd_complete *evt);
void ble_gap_rx_phy_update_complete(const struct ble_hci_ev_le_subev_phy_update_complete *ev);
void ble_gap_enc_event(uint16_t conn_handle, int status,
int security_restored, int bonded);
void ble_gap_passkey_event(uint16_t conn_handle,
@ -118,6 +135,7 @@ int ble_gap_master_in_progress(void);
void ble_gap_preempt(void);
void ble_gap_preempt_done(void);
int ble_gap_terminate_with_conn(struct ble_hs_conn *conn, uint8_t hci_reason);
void ble_gap_conn_broken(uint16_t conn_handle, int reason);
void ble_gap_reset_state(int reason);
int32_t ble_gap_timer(void);

View File

@ -38,6 +38,15 @@ typedef uint8_t ble_hs_conn_flags_t;
#define BLE_HS_CONN_F_TERMINATING 0x02
#define BLE_HS_CONN_F_TX_FRAG 0x04 /* Cur ACL packet partially txed. */
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
#define BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN_REM \
((MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) % (8 * sizeof(uint32_t))) ? 1 : 0)
#define BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN \
(MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM) / (8 * sizeof(uint32_t)) + \
BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN_REM)
#endif
struct ble_hs_conn {
SLIST_ENTRY(ble_hs_conn) bhc_next;
uint16_t bhc_handle;
@ -61,6 +70,9 @@ struct ble_hs_conn {
struct ble_l2cap_chan_list bhc_channels;
struct ble_l2cap_chan *bhc_rx_chan; /* Channel rxing current packet. */
ble_npl_time_t bhc_rx_timeout;
#if MYNEWT_VAL(BLE_L2CAP_COC_MAX_NUM)
uint32_t l2cap_coc_cid_mask[BLE_HS_CONN_L2CAP_COC_CID_MASK_LEN];
#endif
/**
* Count of packets sent over this connection that the controller has not
@ -86,6 +98,10 @@ struct ble_hs_conn {
ble_gap_event_fn *bhc_cb;
void *bhc_cb_arg;
#if MYNEWT_VAL(BLE_PERIODIC_ADV)
struct ble_hs_periodic_sync *psync;
#endif
};
struct ble_hs_conn_addrs {
@ -110,15 +126,19 @@ struct ble_l2cap_chan *ble_hs_conn_chan_find_by_scid(struct ble_hs_conn *conn,
uint16_t cid);
struct ble_l2cap_chan *ble_hs_conn_chan_find_by_dcid(struct ble_hs_conn *conn,
uint16_t cid);
bool ble_hs_conn_chan_exist(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan);
int ble_hs_conn_chan_insert(struct ble_hs_conn *conn,
struct ble_l2cap_chan *chan);
void
ble_hs_conn_delete_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan);
void ble_hs_conn_delete_chan(struct ble_hs_conn *conn,
struct ble_l2cap_chan *chan);
void ble_hs_conn_addrs(const struct ble_hs_conn *conn,
struct ble_hs_conn_addrs *addrs);
int32_t ble_hs_conn_timer(void);
typedef int ble_hs_conn_foreach_fn(struct ble_hs_conn *conn, void *arg);
void ble_hs_conn_foreach(ble_hs_conn_foreach_fn *cb, void *arg);
int ble_hs_conn_init(void);
#ifdef __cplusplus

View File

@ -26,7 +26,7 @@ extern "C" {
#endif
void ble_hs_flow_connection_broken(uint16_t conn_handle);
void ble_hs_flow_fill_acl_usrhdr(struct os_mbuf *om);
void ble_hs_flow_track_data_mbuf(struct os_mbuf *om);
int ble_hs_flow_startup(void);
#ifdef __cplusplus

View File

@ -48,7 +48,7 @@ struct os_mbuf;
struct ble_hs_hci_ack {
int bha_status; /* A BLE_HS_E<...> error; NOT a naked HCI code. */
uint8_t *bha_params;
const uint8_t *bha_params;
int bha_params_len;
uint16_t bha_opcode;
uint8_t bha_hci_handle;
@ -81,11 +81,8 @@ struct hci_periodic_adv_params
extern uint16_t ble_hs_hci_avail_pkts;
int ble_hs_hci_cmd_tx(uint16_t opcode, void *cmd, uint8_t cmd_len,
void *evt_buf, uint8_t evt_buf_len,
uint8_t *out_evt_buf_len);
int ble_hs_hci_cmd_tx_empty_ack(uint16_t opcode, void *cmd, uint8_t cmd_len);
void ble_hs_hci_rx_ack(uint8_t *ack_ev);
int ble_hs_hci_cmd_tx(uint16_t opcode, const void *cmd, uint8_t cmd_len,
void *rsp, uint8_t rsp_len);
void ble_hs_hci_init(void);
void ble_hs_hci_deinit(void);
@ -103,78 +100,11 @@ int ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_pwr);
int ble_hs_hci_util_rand(void *dst, int len);
int ble_hs_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi);
int ble_hs_hci_util_set_random_addr(const uint8_t *addr);
int ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets,
uint16_t tx_time);
int ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om,
struct hci_data_hdr *out_hdr);
int ble_hs_hci_evt_process(uint8_t *data);
int ble_hs_hci_evt_process(const struct ble_hci_ev *ev);
void ble_hs_hci_cmd_write_hdr(uint8_t ogf, uint16_t ocf, uint8_t len,
void *buf);
int ble_hs_hci_cmd_send_buf(uint16_t opcode, void *buf, uint8_t buf_len);
void ble_hs_hci_cmd_build_set_event_mask(uint64_t event_mask,
uint8_t *dst, int dst_len);
void ble_hs_hci_cmd_build_set_event_mask2(uint64_t event_mask, uint8_t *dst,
int dst_len);
void ble_hs_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason,
uint8_t *dst, int dst_len);
void ble_hs_hci_cmd_build_read_rssi(uint16_t handle, uint8_t *dst,
int dst_len);
void ble_hs_hci_cmd_build_le_set_host_chan_class(const uint8_t *chan_map,
uint8_t *dst, int dst_len);
void ble_hs_hci_cmd_build_le_read_chan_map(uint16_t conn_handle,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_le_set_scan_rsp_data(const uint8_t *data, uint8_t len,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_le_set_adv_data(const uint8_t *data, uint8_t len,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_le_set_adv_params(const struct hci_adv_params *adv,
uint8_t *dst, int dst_len);
void ble_hs_hci_cmd_build_le_set_event_mask(uint64_t event_mask,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_le_read_buffer_size(void);
void ble_hs_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst,
int dst_len);
int ble_hs_hci_cmd_le_set_adv_enable(uint8_t enable);
int ble_hs_hci_cmd_build_le_set_scan_params(uint8_t scan_type,
uint16_t scan_itvl,
uint16_t scan_window,
uint8_t own_addr_type,
uint8_t filter_policy,
uint8_t *dst, int dst_len);
void ble_hs_hci_cmd_build_le_set_scan_enable(uint8_t enable,
uint8_t filter_dups,
uint8_t *dst, uint8_t dst_len);
int ble_hs_hci_cmd_le_set_scan_enable(uint8_t enable, uint8_t filter_dups);
int ble_hs_hci_cmd_build_le_create_connection(
const struct hci_create_conn *hcc, uint8_t *cmd, int cmd_len);
int ble_hs_hci_cmd_build_le_add_to_whitelist(const uint8_t *addr,
uint8_t addr_type,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_reset(void);
int ble_hs_hci_cmd_tx_set_ctlr_to_host_fc(uint8_t fc_enable);
int ble_hs_hci_cmd_tx_host_buf_size(const struct hci_host_buf_size *cmd);
int ble_hs_hci_cmd_build_host_num_comp_pkts_entry(
const struct hci_host_num_comp_pkts_entry *entry,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_read_adv_pwr(void);
int ble_hs_hci_cmd_le_create_conn_cancel(void);
int ble_hs_hci_cmd_build_le_conn_update(const struct hci_conn_update *hcu,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_le_conn_update(const struct hci_conn_update *hcu);
void ble_hs_hci_cmd_build_le_lt_key_req_reply(
const struct hci_lt_key_req_reply *hkr, uint8_t *dst, int dst_len);
void ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle,
uint8_t *dst, int dst_len);
void ble_hs_hci_cmd_build_le_conn_param_reply(
const struct hci_conn_param_reply *hcr, uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_le_conn_param_reply(const struct hci_conn_param_reply *hcr);
void ble_hs_hci_cmd_build_le_conn_param_neg_reply(
const struct hci_conn_param_neg_reply *hcn, uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_le_conn_param_neg_reply(
const struct hci_conn_param_neg_reply *hcn);
void ble_hs_hci_cmd_build_le_start_encrypt(const struct hci_start_encrypt *cmd,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_send_buf(uint16_t opcode, const void *buf, uint8_t buf_len);
int ble_hs_hci_set_buf_sz(uint16_t pktlen, uint16_t max_pkts);
void ble_hs_hci_add_avail_pkts(uint16_t delta);
@ -184,145 +114,9 @@ uint16_t ble_hs_hci_util_handle_pb_bc_join(uint16_t handle, uint8_t pb,
int ble_hs_hci_acl_tx_now(struct ble_hs_conn *conn, struct os_mbuf **om);
int ble_hs_hci_acl_tx(struct ble_hs_conn *conn, struct os_mbuf **om);
int ble_hs_hci_cmd_build_set_data_len(uint16_t connection_handle,
uint16_t tx_octets, uint16_t tx_time,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_add_to_resolv_list(
const struct hci_add_dev_to_resolving_list *padd,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_remove_from_resolv_list(
uint8_t addr_type, const uint8_t *addr, uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_read_peer_resolv_addr(
uint8_t peer_identity_addr_type, const uint8_t *peer_identity_addr,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_read_lcl_resolv_addr(
uint8_t local_identity_addr_type, const uint8_t *local_identity_addr,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_set_addr_res_en(
uint8_t enable, uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout(
uint16_t timeout, uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_set_random_addr(const uint8_t *addr,
uint8_t *dst, int dst_len);
#if MYNEWT_VAL(BLE_EXT_ADV)
int ble_hs_hci_cmd_build_le_set_ext_scan_params(uint8_t own_addr_type,
uint8_t filter_policy,
uint8_t phy_mask,
uint8_t phy_count,
struct ble_hs_hci_ext_scan_param *params[],
uint8_t *dst, uint16_t dst_len);
int ble_hs_hci_cmd_build_le_set_ext_scan_enable(uint8_t enable,
uint8_t filter_dups,
uint16_t duration,
uint16_t period,
uint8_t *dst, uint16_t dst_len);
int ble_hs_hci_cmd_build_le_ext_create_conn(const struct hci_ext_create_conn *hcc,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_ext_adv_set_random_addr(uint8_t handle,
const uint8_t *addr,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_ext_adv_data(uint8_t handle, uint8_t operation,
uint8_t frag_pref, struct os_mbuf *data,
uint8_t data_len,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_ext_adv_enable(uint8_t enable, uint8_t sets_num,
const struct hci_ext_adv_set *sets,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_ext_adv_params(uint8_t handle,
const struct hci_ext_adv_params *params,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_ext_adv_remove(uint8_t handle,
uint8_t *cmd, int cmd_len);
#if MYNEWT_VAL(BLE_PERIODIC_ADV)
int
ble_hs_hci_cmd_build_le_periodic_adv_params(uint8_t handle,
const struct hci_periodic_adv_params *params,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_periodic_adv_enable(uint8_t enable,
uint8_t handle,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_periodic_adv_data(uint8_t handle, uint8_t operation,
struct os_mbuf *data,
uint8_t data_len,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_periodic_adv_create_sync(uint8_t filter_policy,
uint8_t adv_sid,
uint8_t adv_add_type,
const uint8_t *adv_addr,
uint16_t skip,
uint16_t sync_timeout,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_periodic_adv_terminate_sync(uint16_t sync_handle,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_add_dev_to_periodic_adv_list(uint8_t adv_add_type,
const uint8_t *adv_addr,
uint8_t adv_sid,
uint8_t *cmd, int cmd_len);
int
ble_hs_hci_cmd_build_le_rem_dev_from_periodic_adv_list(uint8_t adv_add_type,
const uint8_t *adv_addr,
uint8_t adv_sid,
uint8_t *cmd, int cmd_len);
#endif
#endif
int ble_hs_hci_cmd_build_le_enh_recv_test(uint8_t rx_chan, uint8_t phy,
uint8_t mod_idx,
uint8_t *dst, uint16_t dst_len);
int ble_hs_hci_cmd_build_le_enh_trans_test(uint8_t tx_chan,
uint8_t test_data_len,
uint8_t packet_payload_idx,
uint8_t phy,
uint8_t *dst, uint16_t dst_len);
int ble_hs_hci_cmd_build_le_set_priv_mode(const uint8_t *addr, uint8_t addr_type,
uint8_t priv_mode, uint8_t *dst,
uint16_t dst_len);
int ble_hs_hci_cmd_build_le_read_phy(uint16_t conn_handle, uint8_t *dst,
int dst_len);
int ble_hs_hci_cmd_build_le_set_default_phy(uint8_t tx_phys_mask,
uint8_t rx_phys_mask,
uint8_t *dst, int dst_len);
int ble_hs_hci_cmd_build_le_set_phy(uint16_t conn_handle, uint8_t tx_phys_mask,
uint8_t rx_phys_mask, uint16_t phy_opts,
uint8_t *dst, int dst_len);
int ble_hs_hci_frag_num_mbufs(void);
int ble_hs_hci_frag_num_mbufs_free(void);
#if MYNEWT_VAL(BLE_EXT_ADV)
#endif
int ble_hs_hci_cmd_build_le_read_remote_feat(uint16_t handle, uint8_t *dst,
int dst_len);
#ifdef __cplusplus
}
#endif

View File

@ -26,7 +26,6 @@
#include "ble_att_priv.h"
#include "ble_gap_priv.h"
#include "ble_gatt_priv.h"
#include "ble_hs_dbg_priv.h"
#include "ble_hs_hci_priv.h"
#include "ble_hs_atomic_priv.h"
#include "ble_hs_conn_priv.h"
@ -118,7 +117,8 @@ int ble_hs_misc_conn_chan_find(uint16_t conn_handle, uint16_t cid,
int ble_hs_misc_conn_chan_find_reqd(uint16_t conn_handle, uint16_t cid,
struct ble_hs_conn **out_conn,
struct ble_l2cap_chan **out_chan);
uint8_t ble_hs_misc_addr_type_to_id(uint8_t addr_type);
uint8_t ble_hs_misc_own_addr_type_to_id(uint8_t addr_type);
uint8_t ble_hs_misc_peer_addr_type_to_id(uint8_t addr_type);
int ble_hs_misc_restore_irks(void);
int ble_hs_locked_by_cur_task(void);
@ -142,31 +142,6 @@ int ble_mqueue_init(struct ble_mqueue *mq, ble_npl_event_fn *ev_fn, void *ev_arg
struct os_mbuf *ble_mqueue_get(struct ble_mqueue *mq);
int ble_mqueue_put(struct ble_mqueue *mq, struct ble_npl_eventq *evq, struct os_mbuf *om);
#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_DEBUG && !BLE_MONITOR
#define BLE_HS_LOG_CMD(is_tx, cmd_type, cmd_name, conn_handle, \
log_cb, cmd) do \
{ \
BLE_HS_LOG(DEBUG, "%sed %s command: %s; conn=%d ", \
(is_tx) ? "tx" : "rx", (cmd_type), (cmd_name), (conn_handle)); \
(log_cb)(cmd); \
BLE_HS_LOG(DEBUG, "\n"); \
} while (0)
#define BLE_HS_LOG_EMPTY_CMD(is_tx, cmd_type, cmd_name, conn_handle) do \
{ \
BLE_HS_LOG(DEBUG, "%sed %s command: %s; conn=%d ", \
(is_tx) ? "tx" : "rx", (cmd_type), (cmd_name), (conn_handle)); \
BLE_HS_LOG(DEBUG, "\n"); \
} while (0)
#else
#define BLE_HS_LOG_CMD(is_tx, cmd_type, cmd_name, conn_handle, log_cb, cmd)
#define BLE_HS_LOG_EMPTY_CMD(is_tx, cmd_type, cmd_name, conn_handle)
#endif
#if MYNEWT_VAL(BLE_HS_DEBUG)
#define BLE_HS_DBG_ASSERT(x) assert(x)
#define BLE_HS_DBG_ASSERT_EVAL(x) assert(x)

View File

@ -57,25 +57,46 @@ struct ble_l2cap_coc_srv {
int ble_l2cap_coc_init(void);
int ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu,
ble_l2cap_event_fn *cb, void *cb_arg);
int ble_l2cap_coc_create_srv_chan(uint16_t conn_handle, uint16_t psm,
int ble_l2cap_coc_create_srv_chan(struct ble_hs_conn *conn, uint16_t psm,
struct ble_l2cap_chan **chan);
struct ble_l2cap_chan * ble_l2cap_coc_chan_alloc(uint16_t conn_handle,
struct ble_l2cap_chan * ble_l2cap_coc_chan_alloc(struct ble_hs_conn *conn,
uint16_t psm, uint16_t mtu,
struct os_mbuf *sdu_rx,
ble_l2cap_event_fn *cb,
void *cb_arg);
void ble_l2cap_coc_cleanup_chan(struct ble_l2cap_chan *chan);
void ble_l2cap_coc_cleanup_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan);
void ble_l2cap_coc_le_credits_update(uint16_t conn_handle, uint16_t dcid,
uint16_t credits);
int ble_l2cap_coc_recv_ready(struct ble_l2cap_chan *chan,
struct os_mbuf *sdu_rx);
int ble_l2cap_coc_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx);
void ble_l2cap_coc_set_new_mtu_mps(struct ble_l2cap_chan *chan, uint16_t mtu, uint16_t mps);
#else
#define ble_l2cap_coc_init() 0
#define ble_l2cap_coc_create_server(psm, mtu, cb, cb_arg) BLE_HS_ENOTSUP
#define ble_l2cap_coc_recv_ready(chan, sdu_rx) BLE_HS_ENOTSUP
#define ble_l2cap_coc_cleanup_chan(chan)
#define ble_l2cap_coc_send(chan, sdu_tx) BLE_HS_ENOTSUP
static inline int
ble_l2cap_coc_init(void) {
return 0;
}
static inline int
ble_l2cap_coc_create_server(uint16_t psm, uint16_t mtu,
ble_l2cap_event_fn *cb, void *cb_arg) {
return BLE_HS_ENOTSUP;
}
static inline int
ble_l2cap_coc_recv_ready(struct ble_l2cap_chan *chan,
struct os_mbuf *sdu_rx) {
return BLE_HS_ENOTSUP;
}
static inline void
ble_l2cap_coc_cleanup_chan(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan) {
}
static inline int
ble_l2cap_coc_send(struct ble_l2cap_chan *chan, struct os_mbuf *sdu_tx) {
return BLE_HS_ENOTSUP;
}
#endif
#ifdef __cplusplus

View File

@ -65,8 +65,20 @@ struct ble_l2cap_chan {
uint16_t conn_handle;
uint16_t dcid;
uint16_t scid;
uint16_t my_mtu;
uint16_t peer_mtu; /* 0 if not exchanged. */
/* Unions just to avoid confusion on MPS/MTU.
* In CoC context, L2CAP MTU is MPS
*/
union {
uint16_t my_mtu;
uint16_t my_coc_mps;
};
union {
uint16_t peer_mtu;
uint16_t peer_coc_mps;
};
ble_l2cap_chan_flags flags;
struct os_mbuf *rx_buf;
@ -102,7 +114,7 @@ struct os_mbuf *ble_l2cap_prepend_hdr(struct os_mbuf *om, uint16_t cid,
uint16_t len);
struct ble_l2cap_chan *ble_l2cap_chan_alloc(uint16_t conn_handle);
void ble_l2cap_chan_free(struct ble_l2cap_chan *chan);
void ble_l2cap_chan_free(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan);
bool ble_l2cap_is_mtu_req_sent(const struct ble_l2cap_chan *chan);
@ -118,6 +130,13 @@ void ble_l2cap_remove_rx(struct ble_hs_conn *conn, struct ble_l2cap_chan *chan);
int ble_l2cap_init(void);
/* Below experimental API is available when BLE_VERSION >= 52 */
int ble_l2cap_enhanced_connect(uint16_t conn_handle,
uint16_t psm, uint16_t mtu,
uint8_t num, struct os_mbuf *sdu_rx[],
ble_l2cap_event_fn *cb, void *cb_arg);
int ble_l2cap_reconfig(struct ble_l2cap_chan *chans[], uint8_t num, uint16_t new_mtu);
#ifdef __cplusplus
}
#endif

View File

@ -74,6 +74,32 @@ struct ble_l2cap_sig_le_con_rsp {
uint16_t result;
} __attribute__((packed));
struct ble_l2cap_sig_credit_base_connect_req {
uint16_t psm;
uint16_t mtu;
uint16_t mps;
uint16_t credits;
uint16_t scids[0];
} __attribute__((packed));
struct ble_l2cap_sig_credit_base_connect_rsp {
uint16_t mtu;
uint16_t mps;
uint16_t credits;
uint16_t result;
uint16_t dcids[0];
} __attribute__((packed));
struct ble_l2cap_sig_credit_base_reconfig_req {
uint16_t mtu;
uint16_t mps;
uint16_t dcids[0];
} __attribute__((packed));
struct ble_l2cap_sig_credit_base_reconfig_rsp {
uint16_t result;
} __attribute__((packed));
struct ble_l2cap_sig_disc_req {
uint16_t dcid;
uint16_t scid;
@ -107,9 +133,43 @@ int ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan);
int ble_l2cap_sig_le_credits(uint16_t conn_handle, uint16_t scid,
uint16_t credits);
#else
#define ble_l2cap_sig_coc_connect(conn_handle, psm, mtu, sdu_rx, cb, cb_arg) \
BLE_HS_ENOTSUP
#define ble_l2cap_sig_disconnect(chan) BLE_HS_ENOTSUP
static inline int
ble_l2cap_sig_coc_connect(uint16_t conn_handle, uint16_t psm, uint16_t mtu,
struct os_mbuf *sdu_rx,
ble_l2cap_event_fn *cb, void *cb_arg)
{
return BLE_HS_ENOTSUP;
}
static inline int
ble_l2cap_sig_disconnect(struct ble_l2cap_chan *chan)
{
return BLE_HS_ENOTSUP;
}
#endif
#if MYNEWT_VAL(BLE_L2CAP_ENHANCED_COC)
int ble_l2cap_sig_ecoc_connect(uint16_t conn_handle,
uint16_t psm, uint16_t mtu,
uint8_t num, struct os_mbuf *sdu_rx[],
ble_l2cap_event_fn *cb, void *cb_arg);
int ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan *chans[],
uint8_t num, uint16_t new_mtu);
#else
static inline int
ble_l2cap_sig_ecoc_connect(uint16_t conn_handle,
uint16_t psm, uint16_t mtu,
uint8_t num, struct os_mbuf *sdu_rx[],
ble_l2cap_event_fn *cb, void *cb_arg)
{
return BLE_HS_ENOTSUP;
}
static inline int
ble_l2cap_sig_coc_reconfig(uint16_t conn_handle, struct ble_l2cap_chan *chans[],
uint8_t num, uint16_t new_mtu)
{
return BLE_HS_ENOTSUP;
}
#endif
void ble_l2cap_sig_conn_broken(uint16_t conn_handle, int reason);

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