Bluetooth: Mesh: Add Proxy Client Feature
Add Proxy client feature support. Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
This commit is contained in:
parent
ad1e8d89ec
commit
3f3ef659da
13 changed files with 775 additions and 5 deletions
|
@ -63,6 +63,26 @@ struct bt_mesh_proxy_cb {
|
||||||
*/
|
*/
|
||||||
int bt_mesh_proxy_identity_enable(void);
|
int bt_mesh_proxy_identity_enable(void);
|
||||||
|
|
||||||
|
/** @brief Allow Proxy Client to auto connect to a network.
|
||||||
|
*
|
||||||
|
* This API allows a proxy client to auto-connect a given network.
|
||||||
|
*
|
||||||
|
* @param net_idx Network Key Index
|
||||||
|
*
|
||||||
|
* @return 0 on success, or (negative) error code on failure.
|
||||||
|
*/
|
||||||
|
int bt_mesh_proxy_connect(uint16_t net_idx);
|
||||||
|
|
||||||
|
/** @brief Disallow Proxy Client to auto connect to a network.
|
||||||
|
*
|
||||||
|
* This API disallows a proxy client to connect a given network.
|
||||||
|
*
|
||||||
|
* @param net_idx Network Key Index
|
||||||
|
*
|
||||||
|
* @return 0 on success, or (negative) error code on failure.
|
||||||
|
*/
|
||||||
|
int bt_mesh_proxy_disconnect(uint16_t net_idx);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -128,6 +128,7 @@ config BT_MAX_CONN
|
||||||
int "Maximum number of simultaneous connections"
|
int "Maximum number of simultaneous connections"
|
||||||
depends on BT_CONN
|
depends on BT_CONN
|
||||||
range 1 64
|
range 1 64
|
||||||
|
default 2 if BT_MESH_GATT_CLIENT
|
||||||
default 1
|
default 1
|
||||||
help
|
help
|
||||||
Maximum number of simultaneous Bluetooth connections
|
Maximum number of simultaneous Bluetooth connections
|
||||||
|
|
|
@ -84,6 +84,7 @@ config BT_RX_STACK_SIZE
|
||||||
int "Size of the receiving thread stack"
|
int "Size of the receiving thread stack"
|
||||||
depends on BT_HCI_HOST || BT_RECV_IS_RX_THREAD
|
depends on BT_HCI_HOST || BT_RECV_IS_RX_THREAD
|
||||||
default 512 if BT_HCI_RAW
|
default 512 if BT_HCI_RAW
|
||||||
|
default 3092 if BT_MESH_GATT_CLIENT
|
||||||
default 2048 if BT_MESH
|
default 2048 if BT_MESH
|
||||||
default 2048 if BT_AUDIO
|
default 2048 if BT_AUDIO
|
||||||
default 2200 if BT_SETTINGS
|
default 2200 if BT_SETTINGS
|
||||||
|
|
|
@ -44,6 +44,12 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_GATT
|
||||||
pb_gatt_srv.c
|
pb_gatt_srv.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_GATT_CLIENT pb_gatt_cli.c)
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_GATT_CLIENT gatt_cli.c)
|
||||||
|
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROXY_CLIENT proxy_cli.c)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_GATT_PROXY proxy_srv.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_GATT_PROXY proxy_srv.c)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_BT_MESH_GATT proxy_msg.c)
|
zephyr_library_sources_ifdef(CONFIG_BT_MESH_GATT proxy_msg.c)
|
||||||
|
|
|
@ -114,6 +114,10 @@ config BT_MESH_PROXY_MSG_LEN
|
||||||
default 66 if BT_MESH_PB_GATT
|
default 66 if BT_MESH_PB_GATT
|
||||||
default 33 if BT_MESH_GATT_PROXY
|
default 33 if BT_MESH_GATT_PROXY
|
||||||
|
|
||||||
|
config BT_MESH_GATT_CLIENT
|
||||||
|
bool
|
||||||
|
select BT_MESH_GATT
|
||||||
|
|
||||||
config BT_MESH_GATT_SERVER
|
config BT_MESH_GATT_SERVER
|
||||||
bool
|
bool
|
||||||
select BT_MESH_GATT
|
select BT_MESH_GATT
|
||||||
|
@ -135,6 +139,16 @@ config BT_MESH_PB_GATT_USE_DEVICE_NAME
|
||||||
This option includes GAP device name in scan response when
|
This option includes GAP device name in scan response when
|
||||||
the PB-GATT is enabled.
|
the PB-GATT is enabled.
|
||||||
|
|
||||||
|
config BT_MESH_PROXY_CLIENT
|
||||||
|
bool "Proxy client support"
|
||||||
|
select BT_GATT_CLIENT
|
||||||
|
select BT_MESH_GATT_CLIENT
|
||||||
|
depends on BT_CENTRAL
|
||||||
|
help
|
||||||
|
This option enables support for the Mesh GATT Proxy Client,
|
||||||
|
i.e. the ability to act as a proxy between a Mesh GATT Service
|
||||||
|
and a Mesh network.
|
||||||
|
|
||||||
config BT_MESH_GATT_PROXY
|
config BT_MESH_GATT_PROXY
|
||||||
bool "GATT Proxy Service support"
|
bool "GATT Proxy Service support"
|
||||||
select BT_MESH_GATT_SERVER
|
select BT_MESH_GATT_SERVER
|
||||||
|
|
353
subsys/bluetooth/mesh/gatt_cli.c
Normal file
353
subsys/bluetooth/mesh/gatt_cli.c
Normal file
|
@ -0,0 +1,353 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Xiaomi Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <sys/byteorder.h>
|
||||||
|
|
||||||
|
#include <net/buf.h>
|
||||||
|
#include <bluetooth/bluetooth.h>
|
||||||
|
#include <bluetooth/hci.h>
|
||||||
|
#include <bluetooth/uuid.h>
|
||||||
|
#include <bluetooth/conn.h>
|
||||||
|
#include <bluetooth/gatt.h>
|
||||||
|
#include <bluetooth/mesh.h>
|
||||||
|
|
||||||
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_PROXY)
|
||||||
|
#define LOG_MODULE_NAME bt_mesh_gatt_client
|
||||||
|
#include "common/log.h"
|
||||||
|
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "adv.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "rpl.h"
|
||||||
|
#include "transport.h"
|
||||||
|
#include "host/ecc.h"
|
||||||
|
#include "prov.h"
|
||||||
|
#include "beacon.h"
|
||||||
|
#include "foundation.h"
|
||||||
|
#include "access.h"
|
||||||
|
#include "proxy.h"
|
||||||
|
#include "proxy_msg.h"
|
||||||
|
#include "proxy_cli.h"
|
||||||
|
#include "gatt_cli.h"
|
||||||
|
|
||||||
|
static struct bt_mesh_gatt_server {
|
||||||
|
struct bt_conn *conn;
|
||||||
|
uint16_t svc_start_handle;
|
||||||
|
uint16_t data_in_handle;
|
||||||
|
const struct bt_mesh_gatt_cli *gatt;
|
||||||
|
|
||||||
|
union {
|
||||||
|
void *user_data;
|
||||||
|
struct bt_gatt_discover_params discover;
|
||||||
|
struct bt_gatt_subscribe_params subscribe;
|
||||||
|
};
|
||||||
|
} servers[CONFIG_BT_MAX_CONN];
|
||||||
|
|
||||||
|
static struct bt_mesh_gatt_server *get_server(struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
return &servers[bt_conn_index(conn)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t notify_func(struct bt_conn *conn,
|
||||||
|
struct bt_gatt_subscribe_params *params,
|
||||||
|
const void *data, uint16_t length)
|
||||||
|
{
|
||||||
|
const uint8_t *val = data;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
BT_WARN("[UNSUBSCRIBED]");
|
||||||
|
params->value_handle = 0U;
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length < 1) {
|
||||||
|
BT_WARN("Too small Proxy PDU");
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)bt_mesh_proxy_msg_recv(conn, val, length);
|
||||||
|
|
||||||
|
return BT_GATT_ITER_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void notify_enabled(struct bt_conn *conn, uint8_t err,
|
||||||
|
struct bt_gatt_write_params *params)
|
||||||
|
{
|
||||||
|
struct bt_mesh_gatt_server *server = get_server(conn);
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
BT_WARN("Enable notify failed(err:%d)", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_DBG("[SUBSCRIBED]");
|
||||||
|
|
||||||
|
server->gatt->link_open(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t discover_func(struct bt_conn *conn,
|
||||||
|
const struct bt_gatt_attr *attr,
|
||||||
|
struct bt_gatt_discover_params *params)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct bt_mesh_gatt_server *server = get_server(conn);
|
||||||
|
|
||||||
|
if (!attr) {
|
||||||
|
BT_DBG("GATT Services Discover complete");
|
||||||
|
(void)memset(params, 0, sizeof(*params));
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_DBG("[ATTRIBUTE UUID 0x%04x] handle %u",
|
||||||
|
BT_UUID_16(server->discover.uuid)->val, attr->handle);
|
||||||
|
|
||||||
|
if (!bt_uuid_cmp(server->discover.uuid, &server->gatt->srv_uuid.uuid)) {
|
||||||
|
server->svc_start_handle = attr->handle;
|
||||||
|
|
||||||
|
server->discover.uuid = &server->gatt->data_in_uuid.uuid;
|
||||||
|
server->discover.start_handle = attr->handle + 1;
|
||||||
|
server->discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &server->discover);
|
||||||
|
if (err) {
|
||||||
|
BT_DBG("Discover GATT data in char failed (err %d)", err);
|
||||||
|
}
|
||||||
|
} else if (!bt_uuid_cmp(server->discover.uuid,
|
||||||
|
&server->gatt->data_in_uuid.uuid)) {
|
||||||
|
server->data_in_handle = attr->handle + 1;
|
||||||
|
|
||||||
|
server->discover.uuid = &server->gatt->data_out_uuid.uuid;
|
||||||
|
server->discover.start_handle = server->svc_start_handle + 1;
|
||||||
|
server->discover.type = BT_GATT_DISCOVER_CHARACTERISTIC;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &server->discover);
|
||||||
|
if (err) {
|
||||||
|
BT_DBG("Discover GATT data out char failed (err %d)", err);
|
||||||
|
}
|
||||||
|
} else if (!bt_uuid_cmp(server->discover.uuid,
|
||||||
|
&server->gatt->data_out_uuid.uuid)) {
|
||||||
|
server->discover.uuid = &server->gatt->data_out_cccd_uuid.uuid;
|
||||||
|
server->discover.start_handle = attr->handle + 2;
|
||||||
|
server->discover.type = BT_GATT_DISCOVER_DESCRIPTOR;
|
||||||
|
|
||||||
|
err = bt_gatt_discover(conn, &server->discover);
|
||||||
|
if (err) {
|
||||||
|
BT_DBG("Discover GATT CCCD failed (err %d)", err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(void)memset(&server->subscribe, 0, sizeof(server->subscribe));
|
||||||
|
|
||||||
|
server->subscribe.notify = notify_func;
|
||||||
|
server->subscribe.write = notify_enabled;
|
||||||
|
server->subscribe.value = BT_GATT_CCC_NOTIFY;
|
||||||
|
server->subscribe.ccc_handle = attr->handle;
|
||||||
|
server->subscribe.value_handle = attr->handle - 1;
|
||||||
|
|
||||||
|
err = bt_gatt_subscribe(conn, &server->subscribe);
|
||||||
|
if (err && err != -EALREADY) {
|
||||||
|
BT_DBG("Subscribe failed (err %d)", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BT_GATT_ITER_STOP;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_mesh_gatt_send(struct bt_conn *conn,
|
||||||
|
const void *data, uint16_t len,
|
||||||
|
bt_gatt_complete_func_t end, void *user_data)
|
||||||
|
{
|
||||||
|
struct bt_mesh_gatt_server *server = get_server(conn);
|
||||||
|
|
||||||
|
BT_DBG("%u bytes: %s", len, bt_hex(data, len));
|
||||||
|
|
||||||
|
return bt_gatt_write_without_response_cb(conn, server->data_in_handle,
|
||||||
|
data, len, false, end, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gatt_connected(struct bt_conn *conn, uint8_t conn_err)
|
||||||
|
{
|
||||||
|
struct bt_mesh_gatt_server *server = get_server(conn);
|
||||||
|
struct bt_conn_info info;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
bt_conn_get_info(conn, &info);
|
||||||
|
if (info.role != BT_CONN_ROLE_CENTRAL ||
|
||||||
|
!server->gatt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (conn_err) {
|
||||||
|
BT_ERR("Failed to connect GATT Services(%u)", conn_err);
|
||||||
|
|
||||||
|
bt_conn_unref(server->conn);
|
||||||
|
server->conn = NULL;
|
||||||
|
|
||||||
|
(void)bt_mesh_scan_enable();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_DBG("conn %p err 0x%02x", (void *)conn, conn_err);
|
||||||
|
|
||||||
|
server->gatt->connected(conn, server->user_data);
|
||||||
|
|
||||||
|
(void)bt_mesh_scan_enable();
|
||||||
|
|
||||||
|
server->discover.uuid = &server->gatt->srv_uuid.uuid;
|
||||||
|
server->discover.func = discover_func;
|
||||||
|
server->discover.start_handle = BT_ATT_FIRST_ATTRIBUTE_HANDLE;
|
||||||
|
server->discover.end_handle = BT_ATT_LAST_ATTRIBUTE_HANDLE;
|
||||||
|
server->discover.type = BT_GATT_DISCOVER_PRIMARY;
|
||||||
|
err = bt_gatt_discover(conn, &server->discover);
|
||||||
|
if (err) {
|
||||||
|
BT_ERR("Unable discover GATT Services (err %d)", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gatt_disconnected(struct bt_conn *conn, uint8_t reason)
|
||||||
|
{
|
||||||
|
struct bt_conn_info info;
|
||||||
|
struct bt_mesh_gatt_server *server = get_server(conn);
|
||||||
|
|
||||||
|
bt_conn_get_info(conn, &info);
|
||||||
|
if (info.role != BT_CONN_ROLE_CENTRAL ||
|
||||||
|
!server->gatt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
server->gatt->disconnected(conn);
|
||||||
|
|
||||||
|
bt_conn_unref(server->conn);
|
||||||
|
|
||||||
|
(void)memset(server, 0, sizeof(struct bt_mesh_gatt_server));
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_mesh_gatt_cli_connect(const bt_addr_le_t *addr,
|
||||||
|
const struct bt_mesh_gatt_cli *gatt,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct bt_conn *conn;
|
||||||
|
struct bt_mesh_gatt_server *server;
|
||||||
|
|
||||||
|
/* Avoid interconnection between proxy client and server */
|
||||||
|
conn = bt_conn_lookup_addr_le(BT_ID_DEFAULT, addr);
|
||||||
|
if (conn) {
|
||||||
|
bt_conn_unref(conn);
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_mesh_scan_disable();
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_DBG("Try to connect services");
|
||||||
|
|
||||||
|
err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN,
|
||||||
|
BT_LE_CONN_PARAM_DEFAULT, &conn);
|
||||||
|
if (err) {
|
||||||
|
BT_ERR("Connection failed (err:%d)", err);
|
||||||
|
|
||||||
|
(void)bt_mesh_scan_enable();
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
server = get_server(conn);
|
||||||
|
server->conn = conn;
|
||||||
|
server->gatt = gatt;
|
||||||
|
server->user_data = user_data;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gatt_advertising_recv(const struct bt_le_scan_recv_info *info,
|
||||||
|
struct net_buf_simple *buf)
|
||||||
|
{
|
||||||
|
uint16_t uuid;
|
||||||
|
|
||||||
|
if (buf->len < 3) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uuid = net_buf_simple_pull_le16(buf);
|
||||||
|
switch (uuid) {
|
||||||
|
#if defined(CONFIG_BT_MESH_PROXY_CLIENT)
|
||||||
|
case BT_UUID_MESH_PROXY_VAL:
|
||||||
|
bt_mesh_proxy_cli_adv_recv(info, buf);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scan_recv(const struct bt_le_scan_recv_info *info,
|
||||||
|
struct net_buf_simple *buf)
|
||||||
|
{
|
||||||
|
if (info->adv_type != BT_GAP_ADV_TYPE_ADV_IND) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt_mesh_proxy_conn_count_get() == CONFIG_BT_MAX_CONN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (buf->len > 1) {
|
||||||
|
struct net_buf_simple_state state;
|
||||||
|
uint8_t len, type;
|
||||||
|
|
||||||
|
len = net_buf_simple_pull_u8(buf);
|
||||||
|
/* Check for early termination */
|
||||||
|
if (len == 0U) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > buf->len) {
|
||||||
|
BT_WARN("AD malformed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_simple_save(buf, &state);
|
||||||
|
|
||||||
|
type = net_buf_simple_pull_u8(buf);
|
||||||
|
|
||||||
|
buf->len = len - 1;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case BT_DATA_SVC_DATA16:
|
||||||
|
gatt_advertising_recv(info, buf);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
net_buf_simple_restore(buf, &state);
|
||||||
|
net_buf_simple_pull(buf, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bt_le_scan_cb scan_cb = {
|
||||||
|
.recv = scan_recv,
|
||||||
|
};
|
||||||
|
|
||||||
|
void bt_mesh_gatt_client_init(void)
|
||||||
|
{
|
||||||
|
bt_le_scan_cb_register(&scan_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_mesh_gatt_client_deinit(void)
|
||||||
|
{
|
||||||
|
bt_le_scan_cb_unregister(&scan_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_CONN_CB_DEFINE(conn_callbacks) = {
|
||||||
|
.connected = gatt_connected,
|
||||||
|
.disconnected = gatt_disconnected,
|
||||||
|
};
|
29
subsys/bluetooth/mesh/gatt_cli.h
Normal file
29
subsys/bluetooth/mesh/gatt_cli.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Xiaomi Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
struct bt_mesh_gatt_cli {
|
||||||
|
struct bt_uuid_16 srv_uuid;
|
||||||
|
struct bt_uuid_16 data_in_uuid;
|
||||||
|
struct bt_uuid_16 data_out_uuid;
|
||||||
|
struct bt_uuid_16 data_out_cccd_uuid;
|
||||||
|
|
||||||
|
void (*connected)(struct bt_conn *conn, void *user_data);
|
||||||
|
void (*link_open)(struct bt_conn *conn);
|
||||||
|
void (*disconnected)(struct bt_conn *conn);
|
||||||
|
};
|
||||||
|
|
||||||
|
int bt_mesh_gatt_cli_connect(const bt_addr_le_t *addr,
|
||||||
|
const struct bt_mesh_gatt_cli *gatt,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
int bt_mesh_gatt_send(struct bt_conn *conn,
|
||||||
|
const void *data, uint16_t len,
|
||||||
|
bt_gatt_complete_func_t end, void *user_data);
|
||||||
|
|
||||||
|
void bt_mesh_gatt_client_init(void);
|
||||||
|
|
||||||
|
void bt_mesh_gatt_client_deinit(void);
|
|
@ -39,6 +39,7 @@
|
||||||
#include "pb_gatt_srv.h"
|
#include "pb_gatt_srv.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "mesh.h"
|
#include "mesh.h"
|
||||||
|
#include "gatt_cli.h"
|
||||||
|
|
||||||
int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx,
|
int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx,
|
||||||
uint8_t flags, uint32_t iv_index, uint16_t addr,
|
uint8_t flags, uint32_t iv_index, uint16_t addr,
|
||||||
|
@ -185,6 +186,10 @@ void bt_mesh_reset(void)
|
||||||
(void)bt_mesh_proxy_gatt_disable();
|
(void)bt_mesh_proxy_gatt_disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_MESH_GATT_CLIENT)) {
|
||||||
|
bt_mesh_gatt_client_deinit();
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
if (IS_ENABLED(CONFIG_BT_SETTINGS)) {
|
||||||
bt_mesh_net_clear();
|
bt_mesh_net_clear();
|
||||||
}
|
}
|
||||||
|
@ -237,6 +242,10 @@ int bt_mesh_suspend(void)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_MESH_GATT_CLIENT)) {
|
||||||
|
bt_mesh_proxy_disconnect(BT_MESH_KEY_ANY);
|
||||||
|
}
|
||||||
|
|
||||||
bt_mesh_hb_suspend();
|
bt_mesh_hb_suspend();
|
||||||
|
|
||||||
if (bt_mesh_beacon_enabled()) {
|
if (bt_mesh_beacon_enabled()) {
|
||||||
|
@ -363,6 +372,10 @@ int bt_mesh_start(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_BT_MESH_GATT_CLIENT)) {
|
||||||
|
bt_mesh_gatt_client_init();
|
||||||
|
}
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) {
|
||||||
bt_mesh_lpn_init();
|
bt_mesh_lpn_init();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "lpn.h"
|
#include "lpn.h"
|
||||||
#include "friend.h"
|
#include "friend.h"
|
||||||
#include "proxy.h"
|
#include "proxy.h"
|
||||||
|
#include "proxy_cli.h"
|
||||||
#include "transport.h"
|
#include "transport.h"
|
||||||
#include "access.h"
|
#include "access.h"
|
||||||
#include "foundation.h"
|
#include "foundation.h"
|
||||||
|
@ -562,6 +563,11 @@ int bt_mesh_net_send(struct bt_mesh_net_tx *tx, struct net_buf *buf,
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Deliver to GATT Proxy Servers if necessary. */
|
||||||
|
if (IS_ENABLED(CONFIG_BT_MESH_PROXY_CLIENT)) {
|
||||||
|
(void)bt_mesh_proxy_cli_relay(buf);
|
||||||
|
}
|
||||||
|
|
||||||
bt_mesh_adv_send(buf, cb, cb_data);
|
bt_mesh_adv_send(buf, cb, cb_data);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
|
@ -18,6 +18,9 @@
|
||||||
.interval_min = BT_GAP_ADV_FAST_INT_MIN_2, \
|
.interval_min = BT_GAP_ADV_FAST_INT_MIN_2, \
|
||||||
.interval_max = BT_GAP_ADV_FAST_INT_MAX_2
|
.interval_max = BT_GAP_ADV_FAST_INT_MAX_2
|
||||||
|
|
||||||
|
#define BT_MESH_ID_TYPE_NET 0x00
|
||||||
|
#define BT_MESH_ID_TYPE_NODE 0x01
|
||||||
|
|
||||||
int bt_mesh_proxy_gatt_enable(void);
|
int bt_mesh_proxy_gatt_enable(void);
|
||||||
int bt_mesh_proxy_gatt_disable(void);
|
int bt_mesh_proxy_gatt_disable(void);
|
||||||
void bt_mesh_proxy_gatt_disconnect(void);
|
void bt_mesh_proxy_gatt_disconnect(void);
|
||||||
|
|
316
subsys/bluetooth/mesh/proxy_cli.c
Normal file
316
subsys/bluetooth/mesh/proxy_cli.c
Normal file
|
@ -0,0 +1,316 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Xiaomi Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr.h>
|
||||||
|
#include <sys/byteorder.h>
|
||||||
|
|
||||||
|
#include <net/buf.h>
|
||||||
|
#include <bluetooth/bluetooth.h>
|
||||||
|
#include <bluetooth/hci.h>
|
||||||
|
#include <bluetooth/uuid.h>
|
||||||
|
#include <bluetooth/conn.h>
|
||||||
|
#include <bluetooth/gatt.h>
|
||||||
|
#include <bluetooth/mesh.h>
|
||||||
|
|
||||||
|
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_PROXY)
|
||||||
|
#define LOG_MODULE_NAME bt_mesh_proxy_client
|
||||||
|
#include "common/log.h"
|
||||||
|
|
||||||
|
#include "mesh.h"
|
||||||
|
#include "adv.h"
|
||||||
|
#include "net.h"
|
||||||
|
#include "rpl.h"
|
||||||
|
#include "transport.h"
|
||||||
|
#include "host/ecc.h"
|
||||||
|
#include "prov.h"
|
||||||
|
#include "beacon.h"
|
||||||
|
#include "foundation.h"
|
||||||
|
#include "access.h"
|
||||||
|
#include "proxy.h"
|
||||||
|
#include "gatt_cli.h"
|
||||||
|
#include "proxy_msg.h"
|
||||||
|
|
||||||
|
static struct bt_mesh_proxy_server {
|
||||||
|
struct bt_mesh_proxy_role *role;
|
||||||
|
bool link_opened;
|
||||||
|
uint16_t net_idx;
|
||||||
|
} servers[CONFIG_BT_MAX_CONN] = {
|
||||||
|
[0 ... (CONFIG_BT_MAX_CONN - 1)] = {
|
||||||
|
.net_idx = BT_MESH_KEY_UNUSED,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool allow_all_subnet;
|
||||||
|
|
||||||
|
static struct bt_mesh_proxy_server *find_proxy_srv(uint16_t net_idx,
|
||||||
|
bool conn, bool disconn)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(servers); i++) {
|
||||||
|
if (!servers[i].role) {
|
||||||
|
if (!disconn) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (!conn) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (servers[i].net_idx == net_idx) {
|
||||||
|
return &servers[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bt_mesh_proxy_server *find_proxy_srv_by_conn(struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(servers); i++) {
|
||||||
|
if (!servers[i].role ||
|
||||||
|
servers[i].role->conn != conn) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &servers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bt_mesh_proxy_cli_relay(struct net_buf *buf)
|
||||||
|
{
|
||||||
|
bool relayed = false;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(servers); i++) {
|
||||||
|
struct bt_mesh_proxy_server *server = &servers[i];
|
||||||
|
|
||||||
|
if (!server->link_opened) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bt_mesh_proxy_relay_send(server->role->conn, buf)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
relayed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return relayed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void proxy_msg_recv(struct bt_mesh_proxy_role *role)
|
||||||
|
{
|
||||||
|
switch (role->msg_type) {
|
||||||
|
case BT_MESH_PROXY_NET_PDU:
|
||||||
|
BT_DBG("Mesh Network PDU");
|
||||||
|
bt_mesh_net_recv(&role->buf, 0, BT_MESH_NET_IF_PROXY);
|
||||||
|
break;
|
||||||
|
case BT_MESH_PROXY_BEACON:
|
||||||
|
BT_DBG("Mesh Beacon PDU");
|
||||||
|
bt_mesh_beacon_recv(&role->buf);
|
||||||
|
break;
|
||||||
|
case BT_MESH_PROXY_CONFIG:
|
||||||
|
BT_DBG("Mesh Configuration PDU");
|
||||||
|
/* TODO */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BT_WARN("Unhandled Message Type 0x%02x", role->msg_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void proxy_connected(struct bt_conn *conn, void *user_data)
|
||||||
|
{
|
||||||
|
struct bt_mesh_proxy_server *srv = user_data;
|
||||||
|
|
||||||
|
srv->role = bt_mesh_proxy_role_setup(conn, bt_mesh_gatt_send,
|
||||||
|
proxy_msg_recv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void proxy_link_open(struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
struct bt_mesh_proxy_server *srv = find_proxy_srv_by_conn(conn);
|
||||||
|
|
||||||
|
srv->link_opened = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void proxy_disconnected(struct bt_conn *conn)
|
||||||
|
{
|
||||||
|
struct bt_mesh_proxy_server *srv = find_proxy_srv_by_conn(conn);
|
||||||
|
|
||||||
|
bt_mesh_proxy_role_cleanup(srv->role);
|
||||||
|
|
||||||
|
srv->role = NULL;
|
||||||
|
srv->link_opened = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct bt_mesh_gatt_cli proxy = {
|
||||||
|
.srv_uuid = BT_UUID_INIT_16(BT_UUID_MESH_PROXY_VAL),
|
||||||
|
.data_in_uuid = BT_UUID_INIT_16(BT_UUID_MESH_PROXY_DATA_IN_VAL),
|
||||||
|
.data_out_uuid = BT_UUID_INIT_16(BT_UUID_MESH_PROXY_DATA_OUT_VAL),
|
||||||
|
.data_out_cccd_uuid = BT_UUID_INIT_16(BT_UUID_GATT_CCC_VAL),
|
||||||
|
|
||||||
|
.connected = proxy_connected,
|
||||||
|
.link_open = proxy_link_open,
|
||||||
|
.disconnected = proxy_disconnected
|
||||||
|
};
|
||||||
|
|
||||||
|
struct find_net_id {
|
||||||
|
const uint8_t *net_id;
|
||||||
|
struct bt_mesh_proxy_server *srv;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool has_net_id(struct bt_mesh_subnet *sub, void *user_data)
|
||||||
|
{
|
||||||
|
struct find_net_id *res = user_data;
|
||||||
|
struct bt_mesh_proxy_server *srv;
|
||||||
|
|
||||||
|
srv = find_proxy_srv(sub->net_idx, true, true);
|
||||||
|
if (srv) {
|
||||||
|
if (srv->role) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else if (!allow_all_subnet) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!srv) {
|
||||||
|
srv = find_proxy_srv(BT_MESH_KEY_UNUSED, false, true);
|
||||||
|
if (!srv) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memcmp(sub->keys[0].net_id, res->net_id, 8) ||
|
||||||
|
(bt_mesh_subnet_has_new_key(sub) &&
|
||||||
|
!memcmp(sub->keys[1].net_id, res->net_id, 8))) {
|
||||||
|
res->srv = srv;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bt_mesh_proxy_cli_adv_recv(const struct bt_le_scan_recv_info *info,
|
||||||
|
struct net_buf_simple *buf)
|
||||||
|
{
|
||||||
|
uint8_t type;
|
||||||
|
struct find_net_id res;
|
||||||
|
struct bt_mesh_subnet *sub;
|
||||||
|
|
||||||
|
type = net_buf_simple_pull_u8(buf);
|
||||||
|
switch (type) {
|
||||||
|
case BT_MESH_ID_TYPE_NET:
|
||||||
|
if (buf->len != 8) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res.net_id = net_buf_simple_pull_mem(buf, 8);
|
||||||
|
res.srv = NULL;
|
||||||
|
|
||||||
|
sub = bt_mesh_subnet_find(has_net_id, (void *)&res);
|
||||||
|
if (sub && res.srv) {
|
||||||
|
(void)bt_mesh_gatt_cli_connect(info->addr, &proxy, res.srv);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case BT_MESH_ID_TYPE_NODE: {
|
||||||
|
/* TODO */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_mesh_proxy_connect(uint16_t net_idx)
|
||||||
|
{
|
||||||
|
struct bt_mesh_proxy_server *srv;
|
||||||
|
|
||||||
|
if (net_idx == BT_MESH_KEY_ANY) {
|
||||||
|
if (allow_all_subnet) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_all_subnet = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
srv = find_proxy_srv(net_idx, true, true);
|
||||||
|
if (srv) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
srv = find_proxy_srv(BT_MESH_KEY_UNUSED, false, true);
|
||||||
|
if (!srv) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
srv->net_idx = net_idx;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bt_mesh_proxy_disconnect(uint16_t net_idx)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct bt_mesh_proxy_server *srv;
|
||||||
|
|
||||||
|
if (net_idx != BT_MESH_KEY_ANY) {
|
||||||
|
srv = find_proxy_srv(net_idx, true, true);
|
||||||
|
if (!srv) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
srv->net_idx = BT_MESH_KEY_UNUSED;
|
||||||
|
|
||||||
|
if (!srv->role) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return bt_conn_disconnect(srv->role->conn,
|
||||||
|
BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allow_all_subnet) {
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_all_subnet = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(servers); i++) {
|
||||||
|
servers[i].net_idx = BT_MESH_KEY_UNUSED;
|
||||||
|
|
||||||
|
if (!servers[i].role) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bt_conn_disconnect(servers[i].role->conn,
|
||||||
|
BT_HCI_ERR_REMOTE_USER_TERM_CONN);
|
||||||
|
if (err) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt)
|
||||||
|
{
|
||||||
|
switch (evt) {
|
||||||
|
case BT_MESH_KEY_DELETED:
|
||||||
|
(void)bt_mesh_proxy_disconnect(sub->net_idx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BT_MESH_SUBNET_CB_DEFINE(proxy_cli) = {
|
||||||
|
.evt_handler = subnet_evt,
|
||||||
|
};
|
11
subsys/bluetooth/mesh/proxy_cli.h
Normal file
11
subsys/bluetooth/mesh/proxy_cli.h
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 Xiaomi Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void bt_mesh_proxy_cli_adv_recv(const struct bt_le_scan_recv_info *info,
|
||||||
|
struct net_buf_simple *buf);
|
||||||
|
|
||||||
|
bool bt_mesh_proxy_cli_relay(struct net_buf *buf);
|
|
@ -397,9 +397,6 @@ int bt_mesh_proxy_identity_enable(void)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ID_TYPE_NET 0x00
|
|
||||||
#define ID_TYPE_NODE 0x01
|
|
||||||
|
|
||||||
#define NODE_ID_LEN 19
|
#define NODE_ID_LEN 19
|
||||||
#define NET_ID_LEN 11
|
#define NET_ID_LEN 11
|
||||||
|
|
||||||
|
@ -434,7 +431,7 @@ static int node_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||||
|
|
||||||
BT_DBG("");
|
BT_DBG("");
|
||||||
|
|
||||||
proxy_svc_data[2] = ID_TYPE_NODE;
|
proxy_svc_data[2] = BT_MESH_ID_TYPE_NODE;
|
||||||
|
|
||||||
err = bt_rand(proxy_svc_data + 11, 8);
|
err = bt_rand(proxy_svc_data + 11, 8);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -473,7 +470,7 @@ static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration)
|
||||||
|
|
||||||
BT_DBG("");
|
BT_DBG("");
|
||||||
|
|
||||||
proxy_svc_data[2] = ID_TYPE_NET;
|
proxy_svc_data[2] = BT_MESH_ID_TYPE_NET;
|
||||||
|
|
||||||
BT_DBG("Advertising with NetId %s",
|
BT_DBG("Advertising with NetId %s",
|
||||||
bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));
|
bt_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue