Merge branch 'feature/gatt_server_improvements_v4.4' into 'release/v4.4'

NimBLE: Added custom GATT Server functionality and encryption (v4.4)

See merge request espressif/esp-idf!22741
This commit is contained in:
Jiang Jiang Jian 2023-03-17 10:53:01 +08:00
commit 4ceb928831
7 changed files with 388 additions and 86 deletions

View File

@ -7,7 +7,9 @@
This example creates GATT client and performs passive scan, it then connects to peripheral device if the device advertises connectability and the device advertises support for the Alert Notification service (0x1811) as primary service UUID.
It performs three GATT operations against the specified peer:
After connection it enables bonding and link encryprion if the `Enable Link Encryption` flag is set in the example config.
It performs six GATT operations against the specified peer:
* Reads the ANS Supported New Alert Category characteristic.
@ -15,11 +17,17 @@ It performs three GATT operations against the specified peer:
* After the write operation is completed, subscribes to notifications for the ANS Unread Alert Status characteristic.
* After the subscribe operation is completed, it subscribes to notifications for a user defined characteristic.
* After this subscribe operation is completed, it writes to the user defined characteristic.
* After the write operation is completed, it reads from the user defined characteristic.
If the peer does not support a required service, characteristic, or descriptor, then the peer lied when it claimed support for the alert notification service! When this happens, or if a GATT procedure fails, this function immediately terminates the connection.
It uses ESP32's Bluetooth controller and NimBLE stack based BLE host.
This example aims at understanding BLE service discovery, connection and characteristic operations.
This example aims at understanding BLE service discovery, connection, encryption and characteristic operations.
To test this demo, use any BLE GATT server app that advertises support for the Alert Notification service (0x1811) and includes it in the GATT database.
@ -40,7 +48,7 @@ idf.py set-target <chip_name>
### Hardware Required
* A development board with ESP32/ESP32-C3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A development board with ESP32/ESP32-C2/ESP32-C3/ESP32-S3 SoC (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.)
* A USB cable for Power supply and programming
See [Development Boards](https://www.espressif.com/en/products/devkits) for more information about it.
@ -79,6 +87,8 @@ GAP procedure initiated: stop advertising.
GAP procedure initiated: discovery; own_addr_type=0 filter_policy=0 passive=1 limited=0 filter_duplicates=1 duration=forever
GAP procedure initiated: connect; peer_addr_type=1 peer_addr=xx:xx:xx:xx:xx:xx scan_itvl=16 scan_window=16 itvl_min=24 itvl_max=40 latency=0 supervision_timeout=256 min_ce_len=16 max_ce_len=768 own_addr_type=0
Connection established
Connection secured
encryption change event; status=0
GATT procedure initiated: discover all services
GATT procedure initiated: discover all characteristics; start_handle=1 end_handle=3
GATT procedure initiated: discover all characteristics; start_handle=20 end_handle=26
@ -92,6 +102,13 @@ GATT procedure initiated: write; att_handle=43 len=2
Read complete; status=0 conn_handle=0 attr_handle=45 value=0x02
Write complete; status=0 conn_handle=0 attr_handle=47
Subscribe complete; status=0 conn_handle=0 attr_handle=43
GATT procedure initiated: write; att_handle=26 len=2
GATT procedure initiated: write; att_handle=25 len=1
GATT procedure initiated: read; att_handle=25
Subscribe to the custom subscribable characteristic complete; status=0 conn_handle=1 attr_handle=26 value=
Write to the custom subscribable characteristic complete; status=0 conn_handle=1 attr_handle=25
received notification; conn_handle=1 attr_handle=25 attr_len=4
Read complete for the subscribable characteristic; status=0 conn_handle=1 attr_handle=25 value=0x19
```
This is the console output on failure (or peripheral does not support New Alert Service category):

View File

@ -12,4 +12,9 @@ menu "Example Configuration"
help
Enable this flag, to perform only stack Init and Deinit in a loop.
config EXAMPLE_ENCRYPTION
bool
prompt "Enable Link Encryption"
help
This enables bonding and encryption after connection has been established.
endmenu

View File

@ -29,12 +29,183 @@
#include "services/gap/ble_svc_gap.h"
#include "blecent.h"
/*** The UUID of the service containing the subscribable characterstic ***/
static const ble_uuid_t * remote_svc_uuid =
BLE_UUID128_DECLARE(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
/*** The UUID of the subscribable chatacteristic ***/
static const ble_uuid_t * remote_chr_uuid =
BLE_UUID128_DECLARE(0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33);
static const char *tag = "NimBLE_BLE_CENT";
static int blecent_gap_event(struct ble_gap_event *event, void *arg);
static uint8_t peer_addr[6];
void ble_store_config_init(void);
/**
* Application Callback. Called when the custom subscribable chatacteristic
* in the remote GATT server is read.
* Expect to get the recently written data.
**/
static int
blecent_on_custom_read(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
MODLOG_DFLT(INFO,
"Read complete for the subscribable characteristic; "
"status=%d conn_handle=%d", error->status, conn_handle);
if (error->status == 0) {
MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle);
print_mbuf(attr->om);
}
MODLOG_DFLT(INFO, "\n");
return 0;
}
/**
* Application Callback. Called when the custom subscribable characteristic
* in the remote GATT server is written to.
* Client has previously subscribed to this characeteristic,
* so expect a notification from the server.
**/
static int
blecent_on_custom_write(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
const struct peer_chr *chr;
const struct peer *peer;
int rc;
MODLOG_DFLT(INFO,
"Write to the custom subscribable characteristic complete; "
"status=%d conn_handle=%d attr_handle=%d\n",
error->status, conn_handle, attr->handle);
peer = peer_find(conn_handle);
chr = peer_chr_find_uuid(peer,
remote_svc_uuid,
remote_chr_uuid);
if (chr == NULL) {
MODLOG_DFLT(ERROR,
"Error: Peer doesn't have the custom subscribable characteristic\n");
goto err;
}
/*** Performs a read on the characteristic, the result is handled in blecent_on_new_read callback ***/
rc = ble_gattc_read(conn_handle, chr->chr.val_handle,
blecent_on_custom_read, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR,
"Error: Failed to read the custom subscribable characteristic; "
"rc=%d\n", rc);
goto err;
}
return 0;
err:
/* Terminate the connection */
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}
/**
* Application Callback. Called when the custom subscribable characteristic
* is subscribed to.
**/
static int
blecent_on_custom_subscribe(uint16_t conn_handle,
const struct ble_gatt_error *error,
struct ble_gatt_attr *attr,
void *arg)
{
const struct peer_chr *chr;
uint8_t value;
int rc;
const struct peer *peer;
MODLOG_DFLT(INFO,
"Subscribe to the custom subscribable characteristic complete; "
"status=%d conn_handle=%d", error->status, conn_handle);
if (error->status == 0) {
MODLOG_DFLT(INFO, " attr_handle=%d value=", attr->handle);
print_mbuf(attr->om);
}
MODLOG_DFLT(INFO, "\n");
peer = peer_find(conn_handle);
chr = peer_chr_find_uuid(peer,
remote_svc_uuid,
remote_chr_uuid);
if (chr == NULL) {
MODLOG_DFLT(ERROR, "Error: Peer doesn't have the subscribable characteristic\n");
goto err;
}
/* Write 1 byte to the new characteristic to test if it notifies after subscribing */
value = 0x19;
rc = ble_gattc_write_flat(conn_handle, chr->chr.val_handle,
&value, sizeof(value), blecent_on_custom_write, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR,
"Error: Failed to write to the subscribable characteristic; "
"rc=%d\n", rc);
goto err;
}
return 0;
err:
/* Terminate the connection */
return ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}
/**
* Performs 3 operations on the remote GATT server.
* 1. Subscribes to a characteristic by writing 0x10 to it's CCCD.
* 2. Writes to the characteristic and expect a notification from remote.
* 3. Reads the characteristic and expect to get the recently written information.
**/
static void
blecent_custom_gatt_operations(const struct peer* peer)
{
const struct peer_dsc *dsc;
int rc;
uint8_t value[2];
dsc = peer_dsc_find_uuid(peer,
remote_svc_uuid,
remote_chr_uuid,
BLE_UUID16_DECLARE(BLE_GATT_DSC_CLT_CFG_UUID16));
if (dsc == NULL) {
MODLOG_DFLT(ERROR, "Error: Peer lacks a CCCD for the subscribable characterstic\n");
goto err;
}
/*** Write 0x00 and 0x01 (The subscription code) to the CCCD ***/
value[0] = 1;
value[1] = 0;
rc = ble_gattc_write_flat(peer->conn_handle, dsc->dsc.handle,
value, sizeof(value), blecent_on_custom_subscribe, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR,
"Error: Failed to subscribe to the subscribable characteristic; "
"rc=%d\n", rc);
goto err;
}
return;
err:
/* Terminate the connection */
ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}
/**
* Application callback. Called when the attempt to subscribe to notifications
* for the ANS Unread Alert Status characteristic has completed.
@ -45,10 +216,20 @@ blecent_on_subscribe(uint16_t conn_handle,
struct ble_gatt_attr *attr,
void *arg)
{
struct peer *peer;
MODLOG_DFLT(INFO, "Subscribe complete; status=%d conn_handle=%d "
"attr_handle=%d\n",
error->status, conn_handle, attr->handle);
peer = peer_find(conn_handle);
if (peer == NULL) {
MODLOG_DFLT(ERROR, "Error in finding peer, aborting...");
ble_gap_terminate(conn_handle, BLE_ERR_REM_USER_CONN_TERM);
}
/* Subscribe to, write to, and read the custom characteristic*/
blecent_custom_gatt_operations(peer);
return 0;
}
@ -217,7 +398,7 @@ blecent_on_disc_complete(const struct peer *peer, int status, void *arg)
"conn_handle=%d\n", status, peer->conn_handle);
/* Now perform three GATT procedures against the peer: read,
* write, and subscribe to notifications.
* write, and subscribe to notifications for the ANS service.
*/
blecent_read_write_subscribe(peer);
}
@ -409,13 +590,30 @@ blecent_gap_event(struct ble_gap_event *event, void *arg)
return 0;
}
/* Perform service discovery. */
rc = peer_disc_all(event->connect.conn_handle,
blecent_on_disc_complete, NULL);
#if CONFIG_EXAMPLE_ENCRYPTION
/** Initiate security - It will perform
* Pairing (Exchange keys)
* Bonding (Store keys)
* Encryption (Enable encryption)
* Will invoke event BLE_GAP_EVENT_ENC_CHANGE
**/
rc = ble_gap_security_initiate(event->connect.conn_handle);
if (rc != 0) {
MODLOG_DFLT(INFO, "Security could not be initiated, rc = %d\n", rc);
return ble_gap_terminate(event->connect.conn_handle,
BLE_ERR_REM_USER_CONN_TERM);
} else {
MODLOG_DFLT(INFO, "Connection secured\n");
}
#else
/* Perform service discovery */
rc = peer_disc_all(event->connect.conn_handle,
blecent_on_disc_complete, NULL);
if(rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
return 0;
}
#endif
} else {
/* Connection attempt failed; resume scanning. */
MODLOG_DFLT(ERROR, "Error: Connection failed; status=%d\n",
@ -450,6 +648,15 @@ blecent_gap_event(struct ble_gap_event *event, void *arg)
rc = ble_gap_conn_find(event->enc_change.conn_handle, &desc);
assert(rc == 0);
print_conn_desc(&desc);
#if CONFIG_EXAMPLE_ENCRYPTION
/*** Go for service discovery after encryption has been successfully enabled ***/
rc = peer_disc_all(event->connect.conn_handle,
blecent_on_disc_complete, NULL);
if (rc != 0) {
MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
return 0;
}
#endif
return 0;
case BLE_GAP_EVENT_NOTIFY_RX:

View File

@ -9,9 +9,9 @@ This example creates GATT server and then starts advertising, waiting to be conn
It uses ESP32's Bluetooth controller and NimBLE stack based BLE host.
This example aims at understanding GATT database configuration, advertisement and SMP related NimBLE APIs.
This example aims at understanding GATT database configuration, handling GATT reads and writes, handling subscribe events, understanding advertisement and SMP related NimBLE APIs.
It also demonstrates security features of NimBLE stack. SMP parameters like I/O capabilities of device, Bonding flag, MITM protection flag and Secure Connection only mode etc., can be configured through menuconfig options.
It also demonstrates security features of NimBLE stack. SMP parameters like I/O capabilities of device, Bonding flag, MITM protection flag and Secure Connection only mode, Enabling Link Encryption etc., can be configured through menuconfig options.
For RPA feature (currently Host based privacy feature is supported), use API `ble_hs_pvcy_rpa_config` to enable/disable host based privacy, `own_addr_type` needs to be set to `BLE_ADDR_RANDOM` to use this feature. Please include `ble_hs_pvcy.h` while using this API. As `ble_hs_pvcy_rpa_config` configures host privacy and sets address in controller, it is necessary to call this API after host-controller are synced (e.g. in `bleprph_on_sync` callback).
@ -83,6 +83,13 @@ peer_id_addr=xx:xx:xx:xx:xx:xx conn_itvl=6 conn_latency=0 supervision_timeout=50
connection updated; status=0 handle=0 our_ota_addr_type=0 our_ota_addr=xx:xx:xx:xx:xx:xx our_id_addr_type=0 our_id_addr=xx:xx:xx:xx:xx:xx
peer_ota_addr_type=1 peer_ota_addr=xx:xx:xx:xx:xx:xx peer_id_addr_type=1 peer_id_addr=xx:xx:xx:xx:xx:xx conn_itvl=39 conn_latency=0 supervision_timeout=500 encrypted=1 authenticated=1 bonded=1
subscribe event; conn_handle=1 attr_handle=19 reason=1 prevn=0 curn=1 previ=0 curi=0
Subscribe to attribute (19) successful
subscribe event; conn_handle=1 attr_handle=25 reason=1 prevn=0 curn=1 previ=0 curi=0
Subscribe to attribute (25) successful
GATT procedure initiated: notify; att_handle=25
Notification sent succesfully
```
## Running Python Utility

View File

@ -48,4 +48,9 @@ menu "Example Configuration"
help
Use this option to enable/disable Security Manager Secure Connection 4.2 feature.
config EXAMPLE_ENCRYPTION
bool
prompt "Enable Link Encryption"
help
This adds Encrypted Read and Write permissions in the custom GATT server.
endmenu

View File

@ -27,54 +27,62 @@
#include "bleprph.h"
#include "services/ans/ble_svc_ans.h"
/**
* The vendor specific security test service consists of two characteristics:
* o random-number-generator: generates a random 32-bit number each time
* it is read. This characteristic can only be read over an encrypted
* connection.
* o static-value: a single-byte characteristic that can always be read,
* but can only be written over an encrypted connection.
*/
/*** Maximum number of characteristics with the notify flag ***/
#define MAX_NOTIFY 5
/* 59462f12-9543-9999-12c8-58b459a2712d */
static const ble_uuid128_t gatt_svr_svc_sec_test_uuid =
static const ble_uuid128_t gatt_svr_svc_uuid =
BLE_UUID128_INIT(0x2d, 0x71, 0xa2, 0x59, 0xb4, 0x58, 0xc8, 0x12,
0x99, 0x99, 0x43, 0x95, 0x12, 0x2f, 0x46, 0x59);
/* 5c3a659e-897e-45e1-b016-007107c96df6 */
static const ble_uuid128_t gatt_svr_chr_sec_test_rand_uuid =
BLE_UUID128_INIT(0xf6, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
/* A characteristic that can be subscribed to */
static uint8_t gatt_svr_chr_val;
static uint16_t gatt_svr_chr_val_handle;
static const ble_uuid128_t gatt_svr_chr_uuid =
BLE_UUID128_INIT(0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11,
0x22, 0x22, 0x22, 0x22, 0x33, 0x33, 0x33, 0x33);
/* 5c3a659e-897e-45e1-b016-007107c96df7 */
static const ble_uuid128_t gatt_svr_chr_sec_test_static_uuid =
BLE_UUID128_INIT(0xf7, 0x6d, 0xc9, 0x07, 0x71, 0x00, 0x16, 0xb0,
0xe1, 0x45, 0x7e, 0x89, 0x9e, 0x65, 0x3a, 0x5c);
static uint8_t gatt_svr_sec_test_static_val;
/* A custom descriptor */
static uint8_t gatt_svr_dsc_val;
static const ble_uuid128_t gatt_svr_dsc_uuid =
BLE_UUID128_INIT(0x01, 0x01, 0x01, 0x01, 0x12, 0x12, 0x12, 0x12,
0x23, 0x23, 0x23, 0x23, 0x34, 0x34, 0x34, 0x34);
static int
gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt,
void *arg);
gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt,
void *arg);
static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
{
/*** Service: Security test. */
/*** Service ***/
.type = BLE_GATT_SVC_TYPE_PRIMARY,
.uuid = &gatt_svr_svc_sec_test_uuid.u,
.uuid = &gatt_svr_svc_uuid.u,
.characteristics = (struct ble_gatt_chr_def[])
{ {
/*** Characteristic: Random number generator. */
.uuid = &gatt_svr_chr_sec_test_rand_uuid.u,
.access_cb = gatt_svr_chr_access_sec_test,
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ_ENC,
}, {
/*** Characteristic: Static value. */
.uuid = &gatt_svr_chr_sec_test_static_uuid.u,
.access_cb = gatt_svr_chr_access_sec_test,
.flags = BLE_GATT_CHR_F_READ |
BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_WRITE_ENC,
/*** This characteristic can be subscribed to by writing 0x00 and 0x01 to the CCCD ***/
.uuid = &gatt_svr_chr_uuid.u,
.access_cb = gatt_svc_access,
#if CONFIG_EXAMPLE_ENCRYPTION
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE |
BLE_GATT_CHR_F_READ_ENC | BLE_GATT_CHR_F_WRITE_ENC |
BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
#else
.flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_WRITE | BLE_GATT_CHR_F_NOTIFY | BLE_GATT_CHR_F_INDICATE,
#endif
.val_handle = &gatt_svr_chr_val_handle,
.descriptors = (struct ble_gatt_dsc_def[])
{ {
.uuid = &gatt_svr_dsc_uuid.u,
#if CONFIG_EXAMPLE_ENCRYPTION
.att_flags = BLE_ATT_F_READ | BLE_ATT_F_READ_ENC,
#else
.att_flags = BLE_ATT_F_READ,
#endif
.access_cb = gatt_svc_access,
}, {
0, /* No more descriptors in this characteristic */
}
},
}, {
0, /* No more characteristics in this service. */
}
@ -87,8 +95,8 @@ static const struct ble_gatt_svc_def gatt_svr_svcs[] = {
};
static int
gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
void *dst, uint16_t *len)
gatt_svr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
void *dst, uint16_t *len)
{
uint16_t om_len;
int rc;
@ -106,52 +114,90 @@ gatt_svr_chr_write(struct os_mbuf *om, uint16_t min_len, uint16_t max_len,
return 0;
}
/**
* Access callback whenever a characteristic/descriptor is read or written to.
* Here reads and writes need to be handled.
* ctxt->op tells weather the operation is read or write and
* weather it is on a characteristic or descriptor,
* ctxt->dsc->uuid tells which characteristic/descriptor is accessed.
* attr_handle give the value handle of the attribute being accessed.
* Accordingly do:
* Append the value to ctxt->om if the operation is READ
* Write ctxt->om to the value if the operation is WRITE
**/
static int
gatt_svr_chr_access_sec_test(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt,
void *arg)
gatt_svc_access(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt, void *arg)
{
const ble_uuid_t *uuid;
int rand_num;
int rc;
uuid = ctxt->chr->uuid;
/* Determine which characteristic is being accessed by examining its
* 128-bit UUID.
*/
if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_rand_uuid.u) == 0) {
assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
/* Respond with a 32-bit random number. */
rand_num = rand();
rc = os_mbuf_append(ctxt->om, &rand_num, sizeof rand_num);
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
if (ble_uuid_cmp(uuid, &gatt_svr_chr_sec_test_static_uuid.u) == 0) {
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
rc = os_mbuf_append(ctxt->om, &gatt_svr_sec_test_static_val,
sizeof gatt_svr_sec_test_static_val);
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
case BLE_GATT_ACCESS_OP_WRITE_CHR:
rc = gatt_svr_chr_write(ctxt->om,
sizeof gatt_svr_sec_test_static_val,
sizeof gatt_svr_sec_test_static_val,
&gatt_svr_sec_test_static_val, NULL);
return rc;
default:
assert(0);
return BLE_ATT_ERR_UNLIKELY;
switch (ctxt->op) {
case BLE_GATT_ACCESS_OP_READ_CHR:
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
MODLOG_DFLT(INFO, "Characteristic read; conn_handle=%d attr_handle=%d\n",
conn_handle, attr_handle);
} else {
MODLOG_DFLT(INFO, "Characteristic read by NimBLE stack; attr_handle=%d\n",
attr_handle);
}
uuid = ctxt->chr->uuid;
if (attr_handle == gatt_svr_chr_val_handle) {
rc = os_mbuf_append(ctxt->om,
&gatt_svr_chr_val,
sizeof(gatt_svr_chr_val));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
goto unknown;
case BLE_GATT_ACCESS_OP_WRITE_CHR:
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
MODLOG_DFLT(INFO, "Characteristic write; conn_handle=%d attr_handle=%d",
conn_handle, attr_handle);
} else {
MODLOG_DFLT(INFO, "Characteristic write by NimBLE stack; attr_handle=%d",
attr_handle);
}
uuid = ctxt->chr->uuid;
if (attr_handle == gatt_svr_chr_val_handle) {
rc = gatt_svr_write(ctxt->om,
sizeof(gatt_svr_chr_val),
sizeof(gatt_svr_chr_val),
&gatt_svr_chr_val, NULL);
ble_gatts_chr_updated(attr_handle);
MODLOG_DFLT(INFO, "Notification/Indication scheduled for "
"all subscribed peers.\n");
return rc;
}
goto unknown;
case BLE_GATT_ACCESS_OP_READ_DSC:
if (conn_handle != BLE_HS_CONN_HANDLE_NONE) {
MODLOG_DFLT(INFO, "Descriptor read; conn_handle=%d attr_handle=%d\n",
conn_handle, attr_handle);
} else {
MODLOG_DFLT(INFO, "Descriptor read by NimBLE stack; attr_handle=%d\n",
attr_handle);
}
uuid = ctxt->dsc->uuid;
if (ble_uuid_cmp(uuid, &gatt_svr_dsc_uuid.u) == 0) {
rc = os_mbuf_append(ctxt->om,
&gatt_svr_dsc_val,
sizeof(gatt_svr_chr_val));
return rc == 0 ? 0 : BLE_ATT_ERR_INSUFFICIENT_RES;
}
goto unknown;
case BLE_GATT_ACCESS_OP_WRITE_DSC:
goto unknown;
default:
goto unknown;
}
/* Unknown characteristic; the nimble stack should not have called this
* function.
unknown:
/* Unknown characteristic/descriptor;
* The NimBLE host should not have called this function;
*/
assert(0);
return BLE_ATT_ERR_UNLIKELY;
@ -208,5 +254,8 @@ gatt_svr_init(void)
return rc;
}
/* Setting a value for the read-only descriptor */
gatt_svr_dsc_val = 0x99;
return 0;
}

View File

@ -203,6 +203,15 @@ bleprph_gap_event(struct ble_gap_event *event, void *arg)
MODLOG_DFLT(INFO, "\n");
return 0;
case BLE_GAP_EVENT_NOTIFY_TX:
MODLOG_DFLT(INFO, "notify_tx event; conn_handle=%d attr_handle=%d "
"status=%d is_indication=%d",
event->notify_tx.conn_handle,
event->notify_tx.attr_handle,
event->notify_tx.status,
event->notify_tx.indication);
return 0;
case BLE_GAP_EVENT_SUBSCRIBE:
MODLOG_DFLT(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
"reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
@ -363,8 +372,11 @@ app_main(void)
ble_hs_cfg.sm_sc = 0;
#endif
#ifdef CONFIG_EXAMPLE_BONDING
ble_hs_cfg.sm_our_key_dist = 1;
ble_hs_cfg.sm_their_key_dist = 1;
/* Enable the appropriate bit masks to make sure the keys
* that are needed are exchanged
*/
ble_hs_cfg.sm_our_key_dist = BLE_SM_PAIR_KEY_DIST_ENC;
ble_hs_cfg.sm_their_key_dist = BLE_SM_PAIR_KEY_DIST_ENC;
#endif