diff --git a/include/bluetooth/mesh/proxy.h b/include/bluetooth/mesh/proxy.h index 3c8863f6b61..2167e97d355 100644 --- a/include/bluetooth/mesh/proxy.h +++ b/include/bluetooth/mesh/proxy.h @@ -63,6 +63,26 @@ struct bt_mesh_proxy_cb { */ 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 } #endif diff --git a/subsys/bluetooth/Kconfig b/subsys/bluetooth/Kconfig index 36bd726756f..264c3c0b1d6 100644 --- a/subsys/bluetooth/Kconfig +++ b/subsys/bluetooth/Kconfig @@ -128,6 +128,7 @@ config BT_MAX_CONN int "Maximum number of simultaneous connections" depends on BT_CONN range 1 64 + default 2 if BT_MESH_GATT_CLIENT default 1 help Maximum number of simultaneous Bluetooth connections diff --git a/subsys/bluetooth/host/Kconfig b/subsys/bluetooth/host/Kconfig index f0af97024d9..b345c080889 100644 --- a/subsys/bluetooth/host/Kconfig +++ b/subsys/bluetooth/host/Kconfig @@ -84,6 +84,7 @@ config BT_RX_STACK_SIZE int "Size of the receiving thread stack" depends on BT_HCI_HOST || BT_RECV_IS_RX_THREAD default 512 if BT_HCI_RAW + default 3092 if BT_MESH_GATT_CLIENT default 2048 if BT_MESH default 2048 if BT_AUDIO default 2200 if BT_SETTINGS diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index a02cac7c8b3..d6f0baf2424 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -44,6 +44,12 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_GATT 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_msg.c) diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig index 001a878fb5e..522bc5f9134 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -114,6 +114,10 @@ config BT_MESH_PROXY_MSG_LEN default 66 if BT_MESH_PB_GATT default 33 if BT_MESH_GATT_PROXY +config BT_MESH_GATT_CLIENT + bool + select BT_MESH_GATT + config BT_MESH_GATT_SERVER bool 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 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 bool "GATT Proxy Service support" select BT_MESH_GATT_SERVER diff --git a/subsys/bluetooth/mesh/gatt_cli.c b/subsys/bluetooth/mesh/gatt_cli.c new file mode 100644 index 00000000000..02c4e1d675c --- /dev/null +++ b/subsys/bluetooth/mesh/gatt_cli.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2021 Xiaomi Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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, +}; diff --git a/subsys/bluetooth/mesh/gatt_cli.h b/subsys/bluetooth/mesh/gatt_cli.h new file mode 100644 index 00000000000..37d61074b0f --- /dev/null +++ b/subsys/bluetooth/mesh/gatt_cli.h @@ -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); diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 9f87e645bf9..dfe850f0d61 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -39,6 +39,7 @@ #include "pb_gatt_srv.h" #include "settings.h" #include "mesh.h" +#include "gatt_cli.h" int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, 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(); } + if (IS_ENABLED(CONFIG_BT_MESH_GATT_CLIENT)) { + bt_mesh_gatt_client_deinit(); + } + if (IS_ENABLED(CONFIG_BT_SETTINGS)) { bt_mesh_net_clear(); } @@ -237,6 +242,10 @@ int bt_mesh_suspend(void) return err; } + if (IS_ENABLED(CONFIG_BT_MESH_GATT_CLIENT)) { + bt_mesh_proxy_disconnect(BT_MESH_KEY_ANY); + } + bt_mesh_hb_suspend(); 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)) { bt_mesh_lpn_init(); } else { diff --git a/subsys/bluetooth/mesh/net.c b/subsys/bluetooth/mesh/net.c index b62682bae86..b9bbcf27c99 100644 --- a/subsys/bluetooth/mesh/net.c +++ b/subsys/bluetooth/mesh/net.c @@ -29,6 +29,7 @@ #include "lpn.h" #include "friend.h" #include "proxy.h" +#include "proxy_cli.h" #include "transport.h" #include "access.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; } + /* 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); done: diff --git a/subsys/bluetooth/mesh/proxy.h b/subsys/bluetooth/mesh/proxy.h index a471c86e1bd..1ae8ac4efe7 100644 --- a/subsys/bluetooth/mesh/proxy.h +++ b/subsys/bluetooth/mesh/proxy.h @@ -18,6 +18,9 @@ .interval_min = BT_GAP_ADV_FAST_INT_MIN_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_disable(void); void bt_mesh_proxy_gatt_disconnect(void); diff --git a/subsys/bluetooth/mesh/proxy_cli.c b/subsys/bluetooth/mesh/proxy_cli.c new file mode 100644 index 00000000000..8a2f4eb16bb --- /dev/null +++ b/subsys/bluetooth/mesh/proxy_cli.c @@ -0,0 +1,316 @@ +/* + * Copyright (c) 2021 Xiaomi Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#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, +}; diff --git a/subsys/bluetooth/mesh/proxy_cli.h b/subsys/bluetooth/mesh/proxy_cli.h new file mode 100644 index 00000000000..9f8ec96458d --- /dev/null +++ b/subsys/bluetooth/mesh/proxy_cli.h @@ -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); diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 17a71630f48..d079079fc72 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -397,9 +397,6 @@ int bt_mesh_proxy_identity_enable(void) return 0; } -#define ID_TYPE_NET 0x00 -#define ID_TYPE_NODE 0x01 - #define NODE_ID_LEN 19 #define NET_ID_LEN 11 @@ -434,7 +431,7 @@ static int node_id_adv(struct bt_mesh_subnet *sub, int32_t duration) 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); if (err) { @@ -473,7 +470,7 @@ static int net_id_adv(struct bt_mesh_subnet *sub, int32_t duration) 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_hex(sub->keys[SUBNET_KEY_TX_IDX(sub)].net_id, 8));