blob: 22bc2671bf4681931f5e8772b6ac315f318872de [file]
// SPDX-License-Identifier: LGPL-2.1-or-later
/*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#define _GNU_SOURCE
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <glib.h>
#include "bluetooth/bluetooth.h"
#include "bluetooth/uuid.h"
#include "src/shared/util.h"
#include "src/shared/tester.h"
#include "src/shared/queue.h"
#include "src/shared/att.h"
#include "src/shared/gatt-db.h"
#include "src/shared/gatt-server.h"
#include "src/shared/gatt-client.h"
#include "src/shared/rap.h"
struct test_data_ras {
struct gatt_db *db;
struct bt_gatt_server *server;
struct bt_gatt_client *client;
struct queue *ccc_states;
size_t iovcnt;
struct iovec *iov;
unsigned int ras_id;
struct bt_rap *rap; /* Store rap instance for CS injection */
};
struct test_data_rap {
struct gatt_db *db;
struct bt_rap *rap;
struct bt_gatt_client *client;
size_t iovcnt;
struct iovec *iov;
};
struct ccc_state {
uint16_t handle;
uint16_t value;
};
struct notify {
uint16_t handle, ccc_handle;
uint8_t *value;
uint16_t len;
bt_gatt_server_conf_func_t conf;
void *user_data;
};
#define RAP_GATT_CLIENT_MTU 64
#define iov_data(args...) ((const struct iovec[]) { args })
#define define_test_ras(name, function, args...) \
do { \
const struct iovec iov[] = { args }; \
static struct test_data_ras data; \
data.iovcnt = ARRAY_SIZE(iov); \
data.iov = util_iov_dup(iov, ARRAY_SIZE(iov)); \
tester_add(name, &data, NULL, function, \
test_teardown_ras); \
} while (0)
static void print_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
if (tester_use_debug())
tester_debug("%s%s", prefix, str);
}
static void test_teardown_ras(const void *user_data)
{
struct test_data_ras *data = (void *)user_data;
bt_gatt_server_unref(data->server);
util_iov_free(data->iov, data->iovcnt);
gatt_db_unref(data->db);
bt_rap_unregister(data->ras_id);
queue_destroy(data->ccc_states, free);
tester_teardown_complete();
}
static void test_complete_cb(const void *user_data)
{
tester_test_passed();
}
static bool ccc_state_match(const void *a, const void *b)
{
const struct ccc_state *ccc = a;
uint16_t handle = PTR_TO_UINT(b);
return ccc->handle == handle;
}
static struct ccc_state *find_ccc_state(struct test_data_ras *data,
uint16_t handle)
{
return queue_find(data->ccc_states, ccc_state_match,
UINT_TO_PTR(handle));
}
static struct ccc_state *get_ccc_state(struct test_data_ras *data,
uint16_t handle)
{
struct ccc_state *ccc;
ccc = find_ccc_state(data, handle);
if (ccc)
return ccc;
ccc = new0(struct ccc_state, 1);
ccc->handle = handle;
queue_push_tail(data->ccc_states, ccc);
return ccc;
}
static void gatt_notify_cb(struct gatt_db_attribute *attrib,
struct gatt_db_attribute *ccc,
const uint8_t *value, size_t len,
struct bt_att *att, void *user_data)
{
struct test_data_ras *data = user_data;
struct notify notify;
memset(&notify, 0, sizeof(notify));
notify.handle = gatt_db_attribute_get_handle(attrib);
notify.ccc_handle = gatt_db_attribute_get_handle(ccc);
notify.value = (void *) value;
notify.len = len;
printf("%s: notify.value:%d notify->len:%d\n", __func__,
(int)*(notify.value), notify.len);
if (!bt_gatt_server_send_notification(data->server,
notify.handle, notify.value,
notify.len, false))
printf("%s: Failed to send notification\n", __func__);
}
static void gatt_ccc_write_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
const uint8_t *value, size_t len,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct test_data_ras *data = user_data;
struct ccc_state *ccc;
uint16_t handle;
uint16_t ccc_value;
uint8_t ecode = 0;
handle = gatt_db_attribute_get_handle(attrib);
if (offset) {
ecode = BT_ATT_ERROR_INVALID_OFFSET;
goto done;
}
if (len != 2) {
ecode = BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN;
goto done;
}
ccc_value = get_le16(value);
ccc = get_ccc_state(data, handle);
if (!ccc) {
ecode = BT_ATT_ERROR_UNLIKELY;
goto done;
}
ccc->value = ccc_value;
/* Send write response first */
gatt_db_attribute_write_result(attrib, id, 0);
/* If notifications/indications enabled on Real-time Ranging Data CCCD,
* inject fake HCI CS subevent data to trigger notifications
*/
if (handle == 0x0006 && ccc_value != 0x0000 && data->rap) {
size_t event_size = sizeof(struct rap_ev_cs_subevent_result) +
sizeof(struct cs_step_data);
struct rap_ev_cs_subevent_result *fake_event;
struct cs_mode_zero_data *mode_zero;
if (tester_use_debug())
tester_debug("Injecting fake CS data...");
fake_event = g_malloc0(event_size);
if (!fake_event)
return; /* Already sent write response */
/* Fill in the header fields */
fake_event->conn_hdl = 0x0001;
fake_event->config_id = 0x01;
fake_event->start_acl_conn_evt_counter = 0x0000;
fake_event->proc_counter = 0x0001;
fake_event->freq_comp = 0x0000;
fake_event->ref_pwr_lvl = 0x00;
fake_event->proc_done_status = 0x00;
fake_event->subevt_done_status = 0x00;
fake_event->abort_reason = 0x00;
fake_event->num_ant_paths = 0x01;
fake_event->num_steps_reported = 0x01;
fake_event->step_data[0].step_mode = CS_MODE_ZERO;
fake_event->step_data[0].step_chnl = 0x00;
/* Mode 0: 1+1+1+4 bytes */
fake_event->step_data[0].step_data_length = 4;
mode_zero = &fake_event->step_data[0].step_mode_data.mode_zero_data;
mode_zero->packet_quality = 0x01;
mode_zero->packet_rssi_dbm = 0x02;
mode_zero->packet_ant = 0x03;
mode_zero->init_measured_freq_offset = 0x04;
/* Inject the fake event to trigger notification */
bt_rap_hci_cs_subevent_result_callback(event_size, fake_event,
data->rap);
g_free(fake_event);
}
return;
done:
gatt_db_attribute_write_result(attrib, id, ecode);
}
static void gatt_ccc_read_cb(struct gatt_db_attribute *attrib,
unsigned int id, uint16_t offset,
uint8_t opcode, struct bt_att *att,
void *user_data)
{
struct test_data_ras *data = user_data;
struct ccc_state *ccc;
uint16_t handle;
uint8_t ecode = 0;
uint16_t value = 0;
handle = gatt_db_attribute_get_handle(attrib);
ccc = get_ccc_state(data, handle);
if (!ccc) {
ecode = BT_ATT_ERROR_UNLIKELY;
goto done;
}
value = cpu_to_le16(ccc->value);
done:
gatt_db_attribute_read_result(attrib, id, ecode, (void *)&value,
sizeof(value));
}
static void ras_attached(struct bt_rap *rap, void *user_data)
{
struct test_data_ras *data = user_data;
if (data) {
data->rap = rap;
bt_rap_ref(rap); /* Keep a reference */
}
}
static void ras_detached(struct bt_rap *rap, void *user_data)
{
struct test_data_ras *data = user_data;
if (data && data->rap == rap)
data->rap = NULL;
bt_rap_unref(rap);
}
static void test_server(const void *user_data)
{
struct test_data_ras *data = (void *)user_data;
struct bt_att *att;
struct io *io;
io = tester_setup_io(data->iov, data->iovcnt);
g_assert(io);
tester_io_set_complete_func(test_complete_cb);
att = bt_att_new(io_get_fd(io), false);
g_assert(att);
bt_att_set_security(att, BT_ATT_SECURITY_MEDIUM);
bt_att_set_debug(att, BT_ATT_DEBUG, print_debug, "bt_att:", NULL);
data->db = gatt_db_new();
g_assert(data->db);
gatt_db_ccc_register(data->db, gatt_ccc_read_cb, gatt_ccc_write_cb,
gatt_notify_cb, data);
bt_rap_add_db(data->db);
data->ras_id = bt_rap_register(ras_attached, ras_detached, NULL);
data->server = bt_gatt_server_new(data->db, att, 64, 0);
g_assert(data->server);
bt_gatt_server_set_debug(data->server, print_debug, "bt_gatt_server:",
NULL);
data->ccc_states = queue_new();
tester_io_send();
bt_att_unref(att);
}
/*
* ATT: Exchange MTU Request (0x02) len 2
* Client RX MTU: 64
*
* ATT: Exchange MTU Response (0x03) len 2
* Server RX MTU: 64
*/
#define ATT_EXCHANGE_MTU IOV_DATA(0x02, 0x40, 0x00), \
IOV_DATA(0x03, 0x40, 0x00)
/*
* ATT: Read By Group Type Request (0x10) len 6
* Handle range: 0x0001-0xffff
* Attribute group type: Primary Service (0x2800)
*
* ATT: Read By Group Type Response (0x11) len 7
* Attribute data length: 6
* Attribute group list: 1 entry
* Handle range: 0x0001-0x0012
* UUID: Ranging Service (0x185b)
*
* ATT: Read By Group Type Request (0x10) len 6
* Handle range: 0x0013-0xffff
* Attribute group type: Primary Service (0x2800)
*
* ATT: Error Response (0x01) len 4
* Read By Group Type Request (0x10)
* Handle: 0x0013
* Error: Attribute Not Found (0x0a)
*/
#define DISCOVER_PRIM_SERV_NOTIF \
IOV_DATA(0x10, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28), \
IOV_DATA(0x11, 0x06, 0x01, 0x00, 0x12, 0x00, 0x5b, 0x18), \
IOV_DATA(0x10, 0x13, 0x00, 0xff, 0xff, 0x00, 0x28), \
IOV_DATA(0x01, 0x10, 0x13, 0x00, 0x0a)
/*
* ATT: Find By Type Value Request (0x06) len 8
* Handle range: 0x0001-0xffff
* Attribute type: Primary Service (0x2800)
* UUID: Ranging Service (0x185b)
*
* ATT: Find By Type Value Response (0x07) len 4
* Handle range: 0x0001-0x0012
*
* ATT: Find By Type Value Request (0x06) len 8
* Handle range: 0x0013-0xffff
* Attribute type: Primary Service (0x2800)
* UUID: Ranging Service (0x185b)
*
* ATT: Error Response (0x01) len 4
* Find By Type Value Request (0x06)
* Handle: 0x0013
* Error: Attribute Not Found (0x0a)
*/
#define RAS_FIND_BY_TYPE_VALUE \
IOV_DATA(0x06, 0x01, 0x00, 0xff, 0xff, 0x00, 0x28, 0x5b, 0x18), \
IOV_DATA(0x07, 0x01, 0x00, 0x12, 0x00), \
IOV_DATA(0x06, 0x13, 0x00, 0xff, 0xff, 0x00, 0x28, 0x5b, 0x18), \
IOV_DATA(0x01, 0x06, 0x13, 0x00, 0x0a)
/*
* ATT: Read By Type Request (0x08) len 6
* Handle range: 0x0001-0x0012
* Attribute type: Characteristic (0x2803)
*
* ATT: Read By Type Response (0x09) len 44
* Attribute data length: 7
* Attribute data list: 6 entries
* Handle: 0x0002 - RAS Features
* Value: 020003142c
* Handle: 0x0004 - Real-time Ranging Data
* Value: 300005152c
* Handle: 0x0007 - On-demand Ranging Data
* Value: 300008162c
* Handle: 0x000a - RAS Control Point
* Value: 24000b172c
* Handle: 0x000d - RAS Data Ready
* Value: 32000e182c
* Handle: 0x0010 - RAS Data Overwritten
* Value: 320011192c
*
* ATT: Read By Type Request (0x08) len 6
* Handle range: 0x0011-0x0012
* Attribute type: Characteristic (0x2803)
*
* ATT: Error Response (0x01) len 4
* Read By Type Request (0x08)
* Handle: 0x0011
* Error: Attribute Not Found (0x0a)
*/
#define DISC_RAS_CHAR_AFTER_TYPE \
IOV_DATA(0x08, 0x01, 0x00, 0x12, 0x00, 0x03, 0x28), \
IOV_DATA(0x09, 0x07, \
0x02, 0x00, 0x02, 0x03, 0x00, 0x14, 0x2c, \
0x04, 0x00, 0x30, 0x05, 0x00, 0x15, 0x2c, \
0x07, 0x00, 0x30, 0x08, 0x00, 0x16, 0x2c, \
0x0a, 0x00, 0x24, 0x0b, 0x00, 0x17, 0x2c, \
0x0d, 0x00, 0x32, 0x0e, 0x00, 0x18, 0x2c, \
0x10, 0x00, 0x32, 0x11, 0x00, 0x19, 0x2c), \
IOV_DATA(0x08, 0x11, 0x00, 0x12, 0x00, 0x03, 0x28), \
IOV_DATA(0x01, 0x08, 0x11, 0x00, 0x0a)
/*
* ATT: Find Information Request (0x04) len 4
* Handle range: 0x0006-0x0012
*
* ATT: Find Information Response (0x05) len 53
* Format: UUID-16 (0x01)
* Handle: 0x0006
* UUID: Client Characteristic Configuration (0x2902)
* Handle: 0x0007
* UUID: Characteristic (0x2803)
* Handle: 0x0008
* UUID: On-demand Ranging Data (0x2c16)
* Handle: 0x0009
* UUID: Client Characteristic Configuration (0x2902)
* Handle: 0x000a
* UUID: Characteristic (0x2803)
* Handle: 0x000b
* UUID: RAS Control Point (0x2c17)
* Handle: 0x000c
* UUID: Client Characteristic Configuration (0x2902)
* Handle: 0x000d
* UUID: Characteristic (0x2803)
* Handle: 0x000e
* UUID: RAS Data Ready (0x2c18)
* Handle: 0x000f
* UUID: Client Characteristic Configuration (0x2902)
* Handle: 0x0010
* UUID: Characteristic (0x2803)
* Handle: 0x0011
* UUID: RAS Data Overwritten (0x2c19)
* Handle: 0x0012
* UUID: Client Characteristic Configuration (0x2902)
*
* ATT: Find Information Request (0x04) len 4
* Handle range: 0x0013-0x0013
*
* ATT: Error Response (0x01) len 4
* Find Information Request (0x04)
* Handle: 0x0013
* Error: Attribute Not Found (0x0a)
*/
#define RAS_FIND_INFO \
IOV_DATA(0x04, 0x06, 0x00, 0x12, 0x00), \
IOV_DATA(0x05, 0x01, \
0x06, 0x00, 0x02, 0x29, \
0x07, 0x00, 0x03, 0x28, \
0x08, 0x00, 0x16, 0x2c, \
0x09, 0x00, 0x02, 0x29, \
0x0a, 0x00, 0x03, 0x28, \
0x0b, 0x00, 0x17, 0x2c, \
0x0c, 0x00, 0x02, 0x29, \
0x0d, 0x00, 0x03, 0x28, \
0x0e, 0x00, 0x18, 0x2c, \
0x0f, 0x00, 0x02, 0x29, \
0x10, 0x00, 0x03, 0x28, \
0x11, 0x00, 0x19, 0x2c, \
0x12, 0x00, 0x02, 0x29), \
IOV_DATA(0x04, 0x13, 0x00, 0x13, 0x00), \
IOV_DATA(0x01, 0x04, 0x13, 0x00, 0x0a)
#define RAS_SR_SGGIT_SER_BV_01_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE
#define RAS_SR_SGGIT_CHA_BV_01_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE
#define RAS_SR_SGGIT_CHA_BV_02_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO
#define RAS_SR_SGGIT_CHA_BV_03_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO
#define RAS_SR_SGGIT_CHA_BV_04_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO
/*
* RAS/SR/RCO/BV-01-C Characteristic Read: RAS Features
*
* ATT: Read Request (0x0a) len 2
* Handle: 0x0003 (RAS Features value handle)
*
* ATT: Read Response (0x0b) len 5
* Value: 0x01 0x00 0x00 0x00
* Feature bits:
* Bit 0: Real-time ranging (1 = supported)
* Bit 1: Retrieve stored results (0 = not supported)
* Bit 2: Abort operation (0 = not supported)
*
* Note: The RAS Features characteristic is registered with
* BT_ATT_PERM_READ | BT_ATT_PERM_READ_ENCRYPT. Since the test sets
* BT_ATT_SECURITY_MEDIUM, the encryption requirement is satisfied
* and the server returns the feature value showing real-time ranging
* support.
*/
#define ATT_READ_RAS_FEATURES \
IOV_DATA(0x0a, 0x03, 0x00), \
IOV_DATA(0x0b, 0x01, 0x00, 0x00, 0x00)
#define RAS_SR_RCO_BV_01_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO, \
ATT_READ_RAS_FEATURES
/*
* RAS Real-time Ranging Data CCCD Configuration
* Round 1: Enable/Disable notifications (CCCD = 0x0001)
* Round 2: Enable/Disable indications (CCCD = 0x0002)
*/
#define RAS_REALTIME_CCCD_CONFIG \
/* Round 1: Enable notifications on Real-time Ranging Data CCCD */ \
/* (handle 0x0006) */ \
IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
IOV_DATA(0x13), \
/* Disable notifications */ \
IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
IOV_DATA(0x13), \
/* Round 2: Enable indications on Real-time Ranging Data CCCD */ \
IOV_DATA(0x12, 0x06, 0x00, 0x02, 0x00), \
IOV_DATA(0x13), \
/* Disable indications */ \
IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
IOV_DATA(0x13)
/*
* Enable both notifications and indications (CCCD = 0x0003)
* Expect notification (0x1b) to be sent, not indication (0x1d)
* Then disable CCCD
*
* Note: This test is currently disabled because the GATT server rejects
* CCCD value 0x0003 (both notifications and indications enabled) before
* reaching the custom callback. The test infrastructure needs to be updated
* to support this scenario.
*/
#define RAS_REALTIME_CCCD_BOTH_ENABLE_DISABLE \
/* Enable notifications only (CCCD = 0x0001) */ \
IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
IOV_DATA(0x13), \
/* Disable CCCD */ \
IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
IOV_DATA(0x13)
/*
* Disconnection/Reconnection simulation for Real-time Ranging Data
* Enable notifications, disable (disconnect), re-enable (reconnect), disable
*/
#define RAS_REALTIME_CCCD_DISCONNECT_RECONNECT \
/* Step 1: Enable notifications */ \
IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
IOV_DATA(0x13), \
/* Step 3: Disable CCCD (simulates disconnection) */ \
IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
IOV_DATA(0x13), \
/* Step 4: Re-enable notifications (simulates reconnection) */ \
IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
IOV_DATA(0x13), \
/* Disable CCCD to clean up */ \
IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
IOV_DATA(0x13)
/*
* RAS/SR/RRD/BV-01-C [Real-time Ranging Data]
* Verify that the IUT can configure CCCD for notifications/indications
* of the Real-time Ranging Data characteristic.
*/
#define RAS_SR_RRD_BV_01_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO, \
RAS_REALTIME_CCCD_CONFIG
/*
* RAS/SR/RRD/BV-03-C [Real-time Ranging Data notifications and indications]
* Verify that the IUT only sends Real-time Ranging Data notifications when
* configured for both notifications and indications (CCCD = 0x0003).
*
* Test Procedure:
* 1. Write 0x0003 to Real-time Ranging Data CCCD (enable both
* notifications and indications)
* 2. Trigger CS Subevent Data (via fake HCI event injection)
* 3. Verify IUT sends only notifications (0x1b), not indications (0x1d)
*/
#define RAS_SR_RRD_BV_03_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO, \
RAS_REALTIME_CCCD_BOTH_ENABLE_DISABLE
/*
* RAS/SR/RRD/BV-05-C [Real-Time Ranging Data disconnection]
* Verify that the IUT does not resume sending Real-time Ranging Data
* notifications or indications after a disconnection occurs.
*
* Test Procedure:
* 1. Enable Real-time Ranging Data notifications
* 2. Trigger CS Subevent Data (IUT sends notifications)
* 3. Disable CCCD (simulates disconnection - CCCD resets to 0x0000)
* 4. Re-enable notifications (simulates reconnection and reconfiguration)
* 5. Verify IUT does not send old ranging data
*
* Note: In a unit test, we simulate disconnection by disabling and re-enabling
* the CCCD. The RAP implementation should clear any pending data when CCCD is
* disabled, ensuring no old data is sent after re-enabling.
*/
#define RAS_SR_RRD_BV_05_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO, \
RAS_REALTIME_CCCD_DISCONNECT_RECONNECT
/*
* RAS/SR/SPE/BI-11-C [Client enables both Real-time Ranging Data and
* On-demand Ranging Data notifications or indications]
*
* Test Purpose:
* Verify that the IUT responds with the Client Characteristic Configuration
* Descriptor Improperly Configured error when both Real-time Ranging Data
* and On-demand Ranging Data notifications or indications are enabled.
*
* Test Procedure:
* 1. Write 0x0001 to Real-time Ranging Data CCCD (enable notifications)
* 2. Write 0x0001 to On-demand Ranging Data CCCD (should fail with 0xFD)
* 3. Read both CCCDs to verify Real-time is 0x0001, On-demand is 0x0000
* 4. Write 0x0000 to Real-time Ranging Data CCCD (disable)
* 5. Write 0x0001 to On-demand Ranging Data CCCD (enable notifications)
* 6. Write 0x0001 to Real-time Ranging Data CCCD (should fail with 0xFD)
* 7. Read both CCCDs to verify Real-time is 0x0000, On-demand is 0x0001
*
* Expected Outcome:
* - Steps 2 and 6: IUT rejects with error code 0xFD
* - Step 3: Real-time CCCD = 0x0001, On-demand CCCD = 0x0000
* - Step 7: Real-time CCCD = 0x0000, On-demand CCCD = 0x0001
*/
#define RAS_SR_SPE_BI_11_C \
ATT_EXCHANGE_MTU, \
DISCOVER_PRIM_SERV_NOTIF, \
RAS_FIND_BY_TYPE_VALUE, \
DISC_RAS_CHAR_AFTER_TYPE, \
RAS_FIND_INFO, \
/* Step 1: Enable notifications on Real-time Ranging Data CCCD */ \
/* (handle 0x0006) */ \
IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
IOV_DATA(0x13), \
/* Step 2: Try to enable notifications on On-demand Ranging Data */ \
/* CCCD (handle 0x0009) - should fail with 0xFD */ \
IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x00), \
IOV_DATA(0x01, 0x12, 0x09, 0x00, 0xFD), \
/* Step 4: Read Real-time Ranging Data CCCD (should be 0x0001) */ \
IOV_DATA(0x0a, 0x06, 0x00), \
IOV_DATA(0x0b, 0x01, 0x00), \
/* Step 4: Read On-demand Ranging Data CCCD (should be 0x0000) */ \
IOV_DATA(0x0a, 0x09, 0x00), \
IOV_DATA(0x0b, 0x00, 0x00), \
/* Step 5: Disable Real-time Ranging Data CCCD */ \
IOV_DATA(0x12, 0x06, 0x00, 0x00, 0x00), \
IOV_DATA(0x13), \
/* Step 6: Enable notifications on On-demand Ranging Data CCCD */ \
IOV_DATA(0x12, 0x09, 0x00, 0x01, 0x00), \
IOV_DATA(0x13), \
/* Step 7: Try to enable notifications on Real-time Ranging Data */ \
/* CCCD - should fail with 0xFD */ \
IOV_DATA(0x12, 0x06, 0x00, 0x01, 0x00), \
IOV_DATA(0x01, 0x12, 0x06, 0x00, 0xFD), \
/* Step 9: Read Real-time Ranging Data CCCD (should be 0x0000) */ \
IOV_DATA(0x0a, 0x06, 0x00), \
IOV_DATA(0x0b, 0x00, 0x00), \
/* Step 9: Read On-demand Ranging Data CCCD (should be 0x0001) */ \
IOV_DATA(0x0a, 0x09, 0x00), \
IOV_DATA(0x0b, 0x01, 0x00)
int main(int argc, char *argv[])
{
tester_init(&argc, &argv);
/* RAS Testcases */
define_test_ras("RAS/SR/SGGIT/SER/BV-01-C", test_server,
RAS_SR_SGGIT_SER_BV_01_C);
define_test_ras("RAS/SR/SGGIT/CHA/BV-01-C", test_server,
RAS_SR_SGGIT_CHA_BV_01_C);
define_test_ras("RAS/SR/SGGIT/CHA/BV-02-C", test_server,
RAS_SR_SGGIT_CHA_BV_02_C);
define_test_ras("RAS/SR/SGGIT/CHA/BV-03-C", test_server,
RAS_SR_SGGIT_CHA_BV_03_C);
define_test_ras("RAS/SR/SGGIT/CHA/BV-04-C", test_server,
RAS_SR_SGGIT_CHA_BV_04_C);
/* RAS Read Characteristic Operations */
define_test_ras("RAS/SR/RCO/BV-01-C", test_server,
RAS_SR_RCO_BV_01_C);
/* RAS Real-time Ranging Data */
define_test_ras("RAS/SR/RRD/BV-01-C", test_server,
RAS_SR_RRD_BV_01_C);
/* RAS Real-time Ranging Data with CS injection */
define_test_ras("RAS/SR/RRD/BV-03-C", test_server,
RAS_SR_RRD_BV_03_C);
define_test_ras("RAS/SR/RRD/BV-05-C", test_server,
RAS_SR_RRD_BV_05_C);
/* RAS Special Procedures - Mutual Exclusivity */
define_test_ras("RAS/SR/SPE/BI-11-C", test_server,
RAS_SR_SPE_BI_11_C);
return tester_run();
}