diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt index 4ad026a0b9a22..a02cac7c8b32e 100644 --- a/subsys/bluetooth/mesh/CMakeLists.txt +++ b/subsys/bluetooth/mesh/CMakeLists.txt @@ -39,9 +39,12 @@ zephyr_library_sources_ifdef(CONFIG_BT_MESH_PROVISIONER provisioner.c) zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_ADV pb_adv.c) -zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_GATT pb_gatt.c) +zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_GATT + pb_gatt.c + pb_gatt_srv.c +) -zephyr_library_sources_ifdef(CONFIG_BT_MESH_GATT_SERVER gatt_services.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 b006e2c488527..16af856ed9886 100644 --- a/subsys/bluetooth/mesh/Kconfig +++ b/subsys/bluetooth/mesh/Kconfig @@ -107,6 +107,12 @@ config BT_MESH_PROXY config BT_MESH_GATT bool +config BT_MESH_PROXY_MSG_LEN + int + depends on BT_MESH_GATT + default 66 if BT_MESH_PB_GATT + default 33 if BT_MESH_GATT_PROXY + config BT_MESH_GATT_SERVER bool select BT_MESH_GATT @@ -120,6 +126,14 @@ config BT_MESH_PB_GATT Enable this option to allow the device to be provisioned over GATT. +config BT_MESH_PB_GATT_USE_DEVICE_NAME + bool "Include Bluetooth device name in scan response" + depends on BT_MESH_PB_GATT + default y + help + This option includes GAP device name in scan response when + the PB-GATT is enabled. + config BT_MESH_GATT_PROXY bool "GATT Proxy Service support" select BT_MESH_GATT_SERVER @@ -158,10 +172,9 @@ config BT_MESH_PROXY_USE_DEVICE_NAME config BT_MESH_PROXY_FILTER_SIZE int "Maximum number of filter entries per Proxy Client" - default 3 if BT_MESH_GATT_PROXY - default 1 + default 3 range 1 32767 - depends on BT_MESH_GATT_SERVER + depends on BT_MESH_GATT_PROXY help This option specifies how many Proxy Filter entries the local node supports. diff --git a/subsys/bluetooth/mesh/adv_ext.c b/subsys/bluetooth/mesh/adv_ext.c index 9f4005b30606b..eb7d40a4d758c 100644 --- a/subsys/bluetooth/mesh/adv_ext.c +++ b/subsys/bluetooth/mesh/adv_ext.c @@ -21,6 +21,7 @@ #include "adv.h" #include "net.h" #include "proxy.h" +#include "pb_gatt_srv.h" /* Convert from ms to 0.625ms units */ #define ADV_INT_FAST_MS 20 @@ -171,13 +172,23 @@ static void send_pending_adv(struct k_work *work) } } + if (!IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER)) { + return; + } + /* No more pending buffers */ - if (IS_ENABLED(CONFIG_BT_MESH_GATT_SERVER)) { - BT_DBG("Proxy Advertising"); - err = bt_mesh_proxy_adv_start(); - if (!err) { - atomic_set_bit(adv.flags, ADV_FLAG_PROXY); + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + err = bt_mesh_proxy_adv_start(); + BT_DBG("Proxy Advertising"); } + } else if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + err = bt_mesh_pb_gatt_adv_start(); + BT_DBG("PB-GATT Advertising"); + } + + if (!err) { + atomic_set_bit(adv.flags, ADV_FLAG_PROXY); } } diff --git a/subsys/bluetooth/mesh/adv_legacy.c b/subsys/bluetooth/mesh/adv_legacy.c index 47aed4dc31767..6933a4912fdd8 100644 --- a/subsys/bluetooth/mesh/adv_legacy.c +++ b/subsys/bluetooth/mesh/adv_legacy.c @@ -28,6 +28,7 @@ #include "host/ecc.h" #include "prov.h" #include "proxy.h" +#include "pb_gatt_srv.h" /* Pre-5.0 controllers enforce a minimum interval of 100ms * whereas 5.0+ controllers can go down to 20ms. @@ -137,8 +138,15 @@ static void adv_thread(void *p1, void *p2, void *p3) * to bt_mesh_adv_start: */ adv_timeout = SYS_FOREVER_MS; - bt_mesh_proxy_adv_start(); - BT_DBG("Proxy Advertising"); + if (bt_mesh_is_provisioned()) { + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + (void)bt_mesh_proxy_adv_start(); + BT_DBG("Proxy Advertising"); + } + } else if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + (void)bt_mesh_pb_gatt_adv_start(); + BT_DBG("PB-GATT Advertising"); + } buf = net_buf_get(&bt_mesh_adv_queue, SYS_TIMEOUT_MS(adv_timeout)); diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 965006f7ff8ef..8ae1d0ea6b3cf 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -36,6 +36,7 @@ #include "access.h" #include "foundation.h" #include "proxy.h" +#include "pb_gatt_srv.h" #include "settings.h" #include "mesh.h" @@ -43,7 +44,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, uint8_t flags, uint32_t iv_index, uint16_t addr, const uint8_t dev_key[16]) { - bool pb_gatt_enabled; int err; BT_INFO("Primary Element: 0x%04x", addr); @@ -54,16 +54,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, return -EALREADY; } - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { - if (bt_mesh_proxy_prov_disable(false) == 0) { - pb_gatt_enabled = true; - } else { - pb_gatt_enabled = false; - } - } else { - pb_gatt_enabled = false; - } - /* * FIXME: * Should net_key and iv_index be over-ridden? @@ -108,11 +98,6 @@ int bt_mesh_provision(const uint8_t net_key[16], uint16_t net_idx, err = bt_mesh_net_create(net_idx, flags, net_key, iv_index); if (err) { atomic_clear_bit(bt_mesh.flags, BT_MESH_VALID); - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && pb_gatt_enabled) { - (void)bt_mesh_proxy_prov_enable(); - } - return err; } @@ -197,7 +182,7 @@ void bt_mesh_reset(void) } if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { - bt_mesh_proxy_gatt_disable(); + (void)bt_mesh_proxy_gatt_disable(); } if (IS_ENABLED(CONFIG_BT_SETTINGS)) { @@ -321,10 +306,6 @@ int bt_mesh_init(const struct bt_mesh_prov *prov, return err; } - if (IS_ENABLED(CONFIG_BT_MESH_GATT)) { - bt_mesh_proxy_init(); - } - if (IS_ENABLED(CONFIG_BT_MESH_PROV)) { err = bt_mesh_prov_init(prov); if (err) { @@ -370,10 +351,16 @@ int bt_mesh_start(void) bt_mesh_beacon_disable(); } - if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY) && - bt_mesh_gatt_proxy_get() != BT_MESH_GATT_PROXY_NOT_SUPPORTED) { - bt_mesh_proxy_gatt_enable(); - bt_mesh_adv_update(); + if (!IS_ENABLED(CONFIG_BT_MESH_PROV) || !bt_mesh_prov_active() || + bt_mesh_prov_link.bearer->type == BT_MESH_PROV_ADV) { + if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { + (void)bt_mesh_pb_gatt_disable(); + } + + if (IS_ENABLED(CONFIG_BT_MESH_GATT_PROXY)) { + (void)bt_mesh_proxy_gatt_enable(); + bt_mesh_adv_update(); + } } if (IS_ENABLED(CONFIG_BT_MESH_LOW_POWER)) { diff --git a/subsys/bluetooth/mesh/pb_gatt.c b/subsys/bluetooth/mesh/pb_gatt.c index 992eebe878544..9216229960535 100644 --- a/subsys/bluetooth/mesh/pb_gatt.c +++ b/subsys/bluetooth/mesh/pb_gatt.c @@ -11,6 +11,7 @@ #include "adv.h" #include "host/ecc.h" #include "prov.h" +#include "pb_gatt_srv.h" #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_PROV) #define LOG_MODULE_NAME bt_mesh_pb_gatt @@ -26,7 +27,6 @@ struct prov_link { const struct prov_bearer_cb *cb; void *cb_data; struct prov_bearer_send_cb comp; - struct net_buf_simple *rx_buf; struct k_work_delayable prot_timer; }; @@ -41,8 +41,6 @@ static void reset_state(void) /* If this fails, the protocol timeout handler will exit early. */ (void)k_work_cancel_delayable(&link.prot_timer); - - link.rx_buf = bt_mesh_proxy_get_buf(); } static void link_closed(enum prov_bearer_link_status status) @@ -119,7 +117,7 @@ int bt_mesh_pb_gatt_close(struct bt_conn *conn) static int link_accept(const struct prov_bearer_cb *cb, void *cb_data) { - (void)bt_mesh_proxy_prov_enable(); + (void)bt_mesh_pb_gatt_enable(); bt_mesh_adv_update(); link.cb = cb; diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.c b/subsys/bluetooth/mesh/pb_gatt_srv.c new file mode 100644 index 0000000000000..f43dc3c29a5da --- /dev/null +++ b/subsys/bluetooth/mesh/pb_gatt_srv.c @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include + +#include +#include +#include +#include +#include + +#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_PROV) +#define LOG_MODULE_NAME bt_mesh_pb_gatt_srv +#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 "pb_gatt_srv.h" + +#if defined(CONFIG_BT_MESH_PB_GATT_USE_DEVICE_NAME) +#define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME +#else +#define ADV_OPT_USE_NAME 0 +#endif + +#define ADV_OPT_PROV \ + (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE | \ + BT_LE_ADV_OPT_ONE_TIME | ADV_OPT_USE_IDENTITY | \ + ADV_OPT_USE_NAME) + +static bool prov_fast_adv; + +static int gatt_send(struct bt_conn *conn, + const void *data, uint16_t len, + bt_gatt_complete_func_t end, void *user_data); + +static struct bt_mesh_proxy_role *cli; +static bool service_registered; + +static void proxy_msg_recv(struct bt_mesh_proxy_role *role) +{ + switch (role->msg_type) { + case BT_MESH_PROXY_PROV: + BT_DBG("Mesh Provisioning PDU"); + bt_mesh_pb_gatt_recv(role->conn, &role->buf); + break; + + default: + BT_WARN("Unhandled Message Type 0x%02x", role->msg_type); + break; + } +} + +static ssize_t gatt_recv(struct bt_conn *conn, + const struct bt_gatt_attr *attr, const void *buf, + uint16_t len, uint16_t offset, uint8_t flags) +{ + const uint8_t *data = buf; + + if (cli->conn != conn) { + BT_ERR("No PB-GATT Client found"); + return -ENOTCONN; + } + + if (len < 1) { + BT_WARN("Too small Proxy PDU"); + return -EINVAL; + } + + if (PDU_TYPE(data) != BT_MESH_PROXY_PROV) { + BT_WARN("Proxy PDU type doesn't match GATT service"); + return -EINVAL; + } + + return bt_mesh_proxy_msg_recv(cli, buf, len); +} + +static void gatt_connected(struct bt_conn *conn, uint8_t err) +{ + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + if (info.role != BT_CONN_ROLE_PERIPHERAL || + !service_registered || bt_mesh_is_provisioned()) { + return; + } + + cli = bt_mesh_proxy_role_setup(conn, gatt_send, proxy_msg_recv); + + BT_DBG("conn %p err 0x%02x", (void *)conn, err); +} + +static void gatt_disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct bt_conn_info info; + + bt_conn_get_info(conn, &info); + if (info.role != BT_CONN_ROLE_PERIPHERAL || + !service_registered) { + return; + } + + cli = NULL; + + bt_mesh_pb_gatt_close(conn); + + if (bt_mesh_is_provisioned()) { + (void)bt_mesh_pb_gatt_disable(); + } +} + +static void prov_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value) +{ + BT_DBG("value 0x%04x", value); +} + +static ssize_t prov_ccc_write(struct bt_conn *conn, + const struct bt_gatt_attr *attr, uint16_t value) +{ + if (cli->conn != conn) { + BT_ERR("No PB-GATT Client found"); + return -ENOTCONN; + } + + BT_DBG("value 0x%04x", value); + + if (value != BT_GATT_CCC_NOTIFY) { + BT_WARN("Client wrote 0x%04x instead enabling notify", value); + return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED); + } + + bt_mesh_pb_gatt_open(conn); + + return sizeof(value); +} + +/* Mesh Provisioning Service Declaration */ +static struct _bt_gatt_ccc prov_ccc = + BT_GATT_CCC_INITIALIZER(prov_ccc_changed, prov_ccc_write, NULL); + +static struct bt_gatt_attr prov_attrs[] = { + BT_GATT_PRIMARY_SERVICE(BT_UUID_MESH_PROV), + + BT_GATT_CHARACTERISTIC(BT_UUID_MESH_PROV_DATA_IN, + BT_GATT_CHRC_WRITE_WITHOUT_RESP, + BT_GATT_PERM_WRITE, NULL, gatt_recv, + NULL), + + BT_GATT_CHARACTERISTIC(BT_UUID_MESH_PROV_DATA_OUT, + BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE, + NULL, NULL, NULL), + BT_GATT_CCC_MANAGED(&prov_ccc, + BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), +}; + +static struct bt_gatt_service prov_svc = BT_GATT_SERVICE(prov_attrs); + +int bt_mesh_pb_gatt_enable(void) +{ + BT_DBG(""); + + if (bt_mesh_is_provisioned()) { + return -ENOTSUP; + } + + if (service_registered) { + return -EBUSY; + } + + (void)bt_gatt_service_register(&prov_svc); + service_registered = true; + prov_fast_adv = true; + + return 0; +} + +int bt_mesh_pb_gatt_disable(void) +{ + BT_DBG(""); + + if (!service_registered) { + return -EALREADY; + } + + bt_gatt_service_unregister(&prov_svc); + service_registered = false; + + bt_mesh_adv_update(); + + return 0; +} + +static uint8_t prov_svc_data[20] = { + BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL), +}; + +static const struct bt_data prov_ad[] = { + BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), + BT_DATA_BYTES(BT_DATA_UUID16_ALL, + BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL)), + BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), +}; + +int bt_mesh_pb_gatt_send(struct bt_conn *conn, struct net_buf_simple *buf, + bt_gatt_complete_func_t end, void *user_data) +{ + if (!cli || cli->conn != conn) { + BT_ERR("No PB-GATT Client found"); + return -ENOTCONN; + } + + return bt_mesh_proxy_msg_send(cli, BT_MESH_PROXY_PROV, buf, end, user_data); +} + +static size_t gatt_prov_adv_create(struct bt_data prov_sd[1]) +{ + const struct bt_mesh_prov *prov = bt_mesh_prov_get(); + size_t uri_len; + + memcpy(prov_svc_data + 2, prov->uuid, 16); + sys_put_be16(prov->oob_info, prov_svc_data + 18); + + if (!prov->uri) { + return 0; + } + + uri_len = strlen(prov->uri); + if (uri_len > 29) { + /* There's no way to shorten an URI */ + BT_WARN("Too long URI to fit advertising packet"); + return 0; + } + + prov_sd[0].type = BT_DATA_URI; + prov_sd[0].data_len = uri_len; + prov_sd[0].data = (const uint8_t *)prov->uri; + + return 1; +} + +static int gatt_send(struct bt_conn *conn, + const void *data, uint16_t len, + bt_gatt_complete_func_t end, void *user_data) +{ + BT_DBG("%u bytes: %s", len, bt_hex(data, len)); + + struct bt_gatt_notify_params params = { + .data = data, + .len = len, + .attr = &prov_attrs[3], + .user_data = user_data, + .func = end, + }; + + return bt_gatt_notify_cb(conn, ¶ms); +} + +int bt_mesh_pb_gatt_adv_start(void) +{ + BT_DBG(""); + + if (!service_registered || bt_mesh_is_provisioned()) { + return -ENOTSUP; + } + + struct bt_le_adv_param fast_adv_param = { + .options = ADV_OPT_PROV, + ADV_FAST_INT, + }; + struct bt_data prov_sd[1]; + size_t prov_sd_len; + int err; + + prov_sd_len = gatt_prov_adv_create(prov_sd); + + if (!prov_fast_adv) { + struct bt_le_adv_param slow_adv_param = { + .options = ADV_OPT_PROV, + ADV_SLOW_INT, + }; + + return bt_mesh_adv_start(&slow_adv_param, SYS_FOREVER_MS, prov_ad, + ARRAY_SIZE(prov_ad), prov_sd, prov_sd_len); + } + + /* Advertise 60 seconds using fast interval */ + err = bt_mesh_adv_start(&fast_adv_param, (60 * MSEC_PER_SEC), + prov_ad, ARRAY_SIZE(prov_ad), + prov_sd, prov_sd_len); + if (!err) { + prov_fast_adv = false; + } + + return err; +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .connected = gatt_connected, + .disconnected = gatt_disconnected, +}; diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.h b/subsys/bluetooth/mesh/pb_gatt_srv.h new file mode 100644 index 0000000000000..105f7b9a3cf82 --- /dev/null +++ b/subsys/bluetooth/mesh/pb_gatt_srv.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2017 Intel Corporation + * Copyright (c) 2021 Lingao Meng + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_PB_GATT_SRV_H_ +#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_PB_GATT_SRV_H_ + +#include + +int bt_mesh_pb_gatt_send(struct bt_conn *conn, struct net_buf_simple *buf, + bt_gatt_complete_func_t end, void *user_data); + +int bt_mesh_pb_gatt_enable(void); +int bt_mesh_pb_gatt_disable(void); + +int bt_mesh_pb_gatt_adv_start(void); + +#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_PB_GATT_SRV_H_ */ diff --git a/subsys/bluetooth/mesh/prov_device.c b/subsys/bluetooth/mesh/prov_device.c index 2bba13aa646b6..dd924bd29d57a 100644 --- a/subsys/bluetooth/mesh/prov_device.c +++ b/subsys/bluetooth/mesh/prov_device.c @@ -37,6 +37,7 @@ #include "access.h" #include "foundation.h" #include "proxy.h" +#include "pb_gatt_srv.h" #include "prov.h" #include "settings.h" @@ -634,6 +635,10 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) return -EALREADY; } + if (bt_mesh_prov_active()) { + return -EBUSY; + } + if (IS_ENABLED(CONFIG_BT_MESH_PB_ADV) && (bearers & BT_MESH_PROV_ADV)) { bt_mesh_beacon_disable(); @@ -642,7 +647,7 @@ int bt_mesh_prov_disable(bt_mesh_prov_bearer_t bearers) if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && (bearers & BT_MESH_PROV_GATT)) { - bt_mesh_proxy_prov_disable(true); + (void)bt_mesh_pb_gatt_disable(); } return 0; diff --git a/subsys/bluetooth/mesh/proxy.h b/subsys/bluetooth/mesh/proxy.h index 43d3c6808c3b6..a471c86e1bdf5 100644 --- a/subsys/bluetooth/mesh/proxy.h +++ b/subsys/bluetooth/mesh/proxy.h @@ -4,21 +4,19 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_H_ -#define ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_H_ +#if defined(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR) +#define ADV_OPT_USE_IDENTITY BT_LE_ADV_OPT_USE_IDENTITY +#else +#define ADV_OPT_USE_IDENTITY 0 +#endif -#include +#define ADV_SLOW_INT \ + .interval_min = BT_GAP_ADV_SLOW_INT_MIN, \ + .interval_max = BT_GAP_ADV_SLOW_INT_MAX -#define BT_MESH_PROXY_NET_PDU 0x00 -#define BT_MESH_PROXY_BEACON 0x01 -#define BT_MESH_PROXY_CONFIG 0x02 -#define BT_MESH_PROXY_PROV 0x03 - -int bt_mesh_pb_gatt_send(struct bt_conn *conn, struct net_buf_simple *buf, - bt_gatt_complete_func_t end, void *user_data); - -int bt_mesh_proxy_prov_enable(void); -int bt_mesh_proxy_prov_disable(bool disconnect); +#define ADV_FAST_INT \ + .interval_min = BT_GAP_ADV_FAST_INT_MIN_2, \ + .interval_max = BT_GAP_ADV_FAST_INT_MAX_2 int bt_mesh_proxy_gatt_enable(void); int bt_mesh_proxy_gatt_disable(void); @@ -26,8 +24,6 @@ void bt_mesh_proxy_gatt_disconnect(void); void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub); -struct net_buf_simple *bt_mesh_proxy_get_buf(void); - int bt_mesh_proxy_adv_start(void); void bt_mesh_proxy_identity_start(struct bt_mesh_subnet *sub); @@ -35,7 +31,3 @@ void bt_mesh_proxy_identity_stop(struct bt_mesh_subnet *sub); bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst); void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, uint16_t addr); - -int bt_mesh_proxy_init(void); - -#endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_H_ */ diff --git a/subsys/bluetooth/mesh/proxy_msg.c b/subsys/bluetooth/mesh/proxy_msg.c index 121f61c7b269a..aaff915a97882 100644 --- a/subsys/bluetooth/mesh/proxy_msg.c +++ b/subsys/bluetooth/mesh/proxy_msg.c @@ -48,6 +48,10 @@ #define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) +static uint8_t __noinit bufs[CONFIG_BT_MAX_CONN * CONFIG_BT_MESH_PROXY_MSG_LEN]; + +static struct bt_mesh_proxy_role roles[CONFIG_BT_MAX_CONN]; + static void proxy_sar_timeout(struct k_work *work) { struct bt_mesh_proxy_role *role; @@ -61,73 +65,6 @@ static void proxy_sar_timeout(struct k_work *work) } } -#if defined(CONFIG_BT_MESH_PROXY) -static void proxy_cfg(struct bt_mesh_proxy_role *role) -{ - NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_NET_MAX_PDU_LEN); - struct bt_mesh_net_rx rx; - int err; - - err = bt_mesh_net_decode(&role->buf, BT_MESH_NET_IF_PROXY_CFG, - &rx, &buf); - if (err) { - BT_ERR("Failed to decode Proxy Configuration (err %d)", err); - return; - } - - rx.local_match = 1U; - - if (bt_mesh_rpl_check(&rx, NULL)) { - BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", - rx.ctx.addr, rx.ctx.recv_dst, rx.seq); - return; - } - - /* Remove network headers */ - net_buf_simple_pull(&buf, BT_MESH_NET_HDR_LEN); - - BT_DBG("%u bytes: %s", buf.len, bt_hex(buf.data, buf.len)); - - if (buf.len < 1) { - BT_WARN("Too short proxy configuration PDU"); - return; - } - - role->cb.recv(role->conn, &rx, &buf); -} -#endif - -static void proxy_complete_pdu(struct bt_mesh_proxy_role *role) -{ - switch (role->msg_type) { -#if defined(CONFIG_BT_MESH_PROXY) - 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"); - proxy_cfg(role); - break; -#endif -#if defined(CONFIG_BT_MESH_PB_GATT) - case BT_MESH_PROXY_PROV: - BT_DBG("Mesh Provisioning PDU"); - bt_mesh_pb_gatt_recv(role->conn, &role->buf); - break; -#endif - default: - BT_WARN("Unhandled Message Type 0x%02x", role->msg_type); - break; - } - - net_buf_simple_reset(&role->buf); -} - ssize_t bt_mesh_proxy_msg_recv(struct bt_mesh_proxy_role *role, const void *buf, uint16_t len) { @@ -142,7 +79,8 @@ ssize_t bt_mesh_proxy_msg_recv(struct bt_mesh_proxy_role *role, role->msg_type = PDU_TYPE(data); net_buf_simple_add_mem(&role->buf, data + 1, len - 1); - proxy_complete_pdu(role); + role->cb.recv(role); + net_buf_simple_reset(&role->buf); break; case SAR_FIRST: @@ -187,7 +125,8 @@ ssize_t bt_mesh_proxy_msg_recv(struct bt_mesh_proxy_role *role, */ (void)k_work_cancel_delayable(&role->sar_timer); net_buf_simple_add_mem(&role->buf, data + 1, len - 1); - proxy_complete_pdu(role); + role->cb.recv(role); + net_buf_simple_reset(&role->buf); break; } @@ -243,7 +182,61 @@ int bt_mesh_proxy_msg_send(struct bt_mesh_proxy_role *role, uint8_t type, return 0; } -void bt_mesh_proxy_msg_init(struct bt_mesh_proxy_role *role) +static void proxy_msg_init(struct bt_mesh_proxy_role *role) { + /* Check if buf has been allocated, in this way, we no longer need + * to repeat the operation. + */ + if (role->buf.__buf) { + net_buf_simple_reset(&role->buf); + return; + } + + net_buf_simple_init_with_data(&role->buf, + &bufs[bt_conn_index(role->conn) * + CONFIG_BT_MESH_PROXY_MSG_LEN], + CONFIG_BT_MESH_PROXY_MSG_LEN); + + net_buf_simple_reset(&role->buf); + k_work_init_delayable(&role->sar_timer, proxy_sar_timeout); } + +struct bt_mesh_proxy_role *bt_mesh_proxy_role_setup(struct bt_conn *conn, + proxy_send_cb_t send, + proxy_recv_cb_t recv) +{ + struct bt_mesh_proxy_role *role; + + role = &roles[bt_conn_index(conn)]; + + role->conn = bt_conn_ref(conn); + proxy_msg_init(role); + + role->cb.recv = recv; + role->cb.send = send; + + return role; +} + +static void gatt_disconnected(struct bt_conn *conn, uint8_t reason) +{ + struct bt_mesh_proxy_role *role; + + BT_DBG("conn %p reason 0x%02x", (void *)conn, reason); + + role = &roles[bt_conn_index(conn)]; + + /* If this fails, the work handler exits early, as + * there's no active connection. + */ + (void)k_work_cancel_delayable(&role->sar_timer); + bt_conn_unref(role->conn); + role->conn = NULL; + + bt_mesh_adv_update(); +} + +BT_CONN_CB_DEFINE(conn_callbacks) = { + .disconnected = gatt_disconnected, +}; diff --git a/subsys/bluetooth/mesh/proxy_msg.h b/subsys/bluetooth/mesh/proxy_msg.h index a3a4e05f6b873..3245c045d3500 100644 --- a/subsys/bluetooth/mesh/proxy_msg.h +++ b/subsys/bluetooth/mesh/proxy_msg.h @@ -18,15 +18,20 @@ #define CFG_FILTER_REMOVE 0x02 #define CFG_FILTER_STATUS 0x03 +#define BT_MESH_PROXY_NET_PDU 0x00 +#define BT_MESH_PROXY_BEACON 0x01 +#define BT_MESH_PROXY_CONFIG 0x02 +#define BT_MESH_PROXY_PROV 0x03 + #define PDU_HDR(sar, type) (sar << 6 | (type & BIT_MASK(6))) +struct bt_mesh_proxy_role; + typedef int (*proxy_send_cb_t)(struct bt_conn *conn, const void *data, uint16_t len, bt_gatt_complete_func_t end, void *user_data); -typedef void (*proxy_recv_cb_t)(struct bt_conn *conn, - struct bt_mesh_net_rx *rx, - struct net_buf_simple *buf); +typedef void (*proxy_recv_cb_t)(struct bt_mesh_proxy_role *role); struct bt_mesh_proxy_role { struct bt_conn *conn; @@ -46,6 +51,8 @@ ssize_t bt_mesh_proxy_msg_recv(struct bt_mesh_proxy_role *role, int bt_mesh_proxy_msg_send(struct bt_mesh_proxy_role *role, uint8_t type, struct net_buf_simple *msg, bt_gatt_complete_func_t end, void *user_data); -void bt_mesh_proxy_msg_init(struct bt_mesh_proxy_role *role); +struct bt_mesh_proxy_role *bt_mesh_proxy_role_setup(struct bt_conn *conn, + proxy_send_cb_t send, + proxy_recv_cb_t recv); #endif /* ZEPHYR_SUBSYS_BLUETOOTH_MESH_PROXY_MSG_H_ */ diff --git a/subsys/bluetooth/mesh/gatt_services.c b/subsys/bluetooth/mesh/proxy_srv.c similarity index 64% rename from subsys/bluetooth/mesh/gatt_services.c rename to subsys/bluetooth/mesh/proxy_srv.c index dcdb0b72ec449..1ab3134e48e7d 100644 --- a/subsys/bluetooth/mesh/gatt_services.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -31,110 +31,45 @@ #include "proxy.h" #include "proxy_msg.h" -/* Mesh Profile 1.0 Section 6.6: - * "The timeout for the SAR transfer is 20 seconds. When the timeout - * expires, the Proxy Server shall disconnect." - */ -#define PROXY_SAR_TIMEOUT K_SECONDS(20) - -#define CLIENT_BUF_SIZE 65 - -#if defined(CONFIG_BT_MESH_DEBUG_USE_ID_ADDR) -#define ADV_OPT_USE_IDENTITY BT_LE_ADV_OPT_USE_IDENTITY -#else -#define ADV_OPT_USE_IDENTITY 0 -#endif - #if defined(CONFIG_BT_MESH_PROXY_USE_DEVICE_NAME) #define ADV_OPT_USE_NAME BT_LE_ADV_OPT_USE_NAME #else #define ADV_OPT_USE_NAME 0 #endif -#define ADV_OPT_PROV \ - (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE | \ - BT_LE_ADV_OPT_ONE_TIME | ADV_OPT_USE_IDENTITY | \ - BT_LE_ADV_OPT_USE_NAME) - -#define ADV_OPT_PROXY \ +#define ADV_OPT_PROXY \ (BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_SCANNABLE | \ BT_LE_ADV_OPT_ONE_TIME | ADV_OPT_USE_IDENTITY | \ ADV_OPT_USE_NAME) -#define ADV_SLOW_INT \ - .interval_min = BT_GAP_ADV_SLOW_INT_MIN, \ - .interval_max = BT_GAP_ADV_SLOW_INT_MAX - -#define ADV_FAST_INT \ - .interval_min = BT_GAP_ADV_FAST_INT_MIN_2, \ - .interval_max = BT_GAP_ADV_FAST_INT_MAX_2 - -#if defined(CONFIG_BT_MESH_GATT_PROXY) static void proxy_send_beacons(struct k_work *work); -static void proxy_filter_recv(struct bt_conn *conn, - struct bt_mesh_net_rx *rx, struct net_buf_simple *buf); -#endif /* CONFIG_BT_MESH_GATT_PROXY */ - -#if defined(CONFIG_BT_MESH_PB_GATT) -static bool prov_fast_adv; -#endif /* CONFIG_BT_MESH_PB_GATT */ - static int proxy_send(struct bt_conn *conn, const void *data, uint16_t len, bt_gatt_complete_func_t end, void *user_data); static struct bt_mesh_proxy_client { - struct bt_mesh_proxy_role cli; + struct bt_mesh_proxy_role *cli; uint16_t filter[CONFIG_BT_MESH_PROXY_FILTER_SIZE]; enum __packed { NONE, ACCEPT, REJECT, - PROV, } filter_type; -#if defined(CONFIG_BT_MESH_GATT_PROXY) struct k_work send_beacons; -#endif /* CONFIG_BT_MESH_GATT_PROXY */ } clients[CONFIG_BT_MAX_CONN] = { [0 ... (CONFIG_BT_MAX_CONN - 1)] = { -#if defined(CONFIG_BT_MESH_GATT_PROXY) .send_beacons = Z_WORK_INITIALIZER(proxy_send_beacons), -#endif /* CONFIG_BT_MESH_GATT_PROXY */ - .cli.cb = { - .send = proxy_send, -#if defined(CONFIG_BT_MESH_GATT_PROXY) - .recv = proxy_filter_recv, -#endif /* CONFIG_BT_MESH_GATT_PROXY */ - }, }, }; -static uint8_t __noinit client_buf_data[CLIENT_BUF_SIZE * CONFIG_BT_MAX_CONN]; - -/* Track which service is enabled */ -static enum { - MESH_GATT_NONE, - MESH_GATT_PROV, - MESH_GATT_PROXY, -} gatt_svc = MESH_GATT_NONE; - +static bool service_registered; static int conn_count; static struct bt_mesh_proxy_client *find_client(struct bt_conn *conn) { - int i; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].cli.conn == conn) { - return &clients[i]; - } - } - - return NULL; + return &clients[bt_conn_index(conn)]; } -#define ATTR_IS_PROV(attr) (attr->user_data != NULL) - static ssize_t gatt_recv(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *buf, uint16_t len, uint16_t offset, uint8_t flags) @@ -142,25 +77,19 @@ static ssize_t gatt_recv(struct bt_conn *conn, const uint8_t *data = buf; struct bt_mesh_proxy_client *client = find_client(conn); - if (!client) { - return -ENOTCONN; - } - if (len < 1) { BT_WARN("Too small Proxy PDU"); return -EINVAL; } - if (ATTR_IS_PROV(attr) != (PDU_TYPE(data) == BT_MESH_PROXY_PROV)) { + if (PDU_TYPE(data) == BT_MESH_PROXY_PROV) { BT_WARN("Proxy PDU type doesn't match GATT service"); return -EINVAL; } - return bt_mesh_proxy_msg_recv(&client->cli, buf, len); + return bt_mesh_proxy_msg_recv(client->cli, buf, len); } - -#if defined(CONFIG_BT_MESH_GATT_PROXY) /* Next subnet in queue to be advertised */ static struct bt_mesh_subnet *beacon_sub; @@ -278,7 +207,7 @@ static void send_filter_status(struct bt_mesh_proxy_client *client, return; } - err = bt_mesh_proxy_msg_send(&client->cli, BT_MESH_PROXY_CONFIG, + err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_CONFIG, buf, NULL, NULL); if (err) { BT_ERR("Failed to send proxy cfg message (err %d)", err); @@ -292,9 +221,6 @@ static void proxy_filter_recv(struct bt_conn *conn, uint8_t opcode; client = find_client(conn); - if (!client) { - return; - } opcode = net_buf_simple_pull_u8(buf); switch (opcode) { @@ -326,6 +252,61 @@ static void proxy_filter_recv(struct bt_conn *conn, } } +static void proxy_cfg(struct bt_mesh_proxy_role *role) +{ + NET_BUF_SIMPLE_DEFINE(buf, BT_MESH_NET_MAX_PDU_LEN); + struct bt_mesh_net_rx rx; + int err; + + err = bt_mesh_net_decode(&role->buf, BT_MESH_NET_IF_PROXY_CFG, + &rx, &buf); + if (err) { + BT_ERR("Failed to decode Proxy Configuration (err %d)", err); + return; + } + + rx.local_match = 1U; + + if (bt_mesh_rpl_check(&rx, NULL)) { + BT_WARN("Replay: src 0x%04x dst 0x%04x seq 0x%06x", + rx.ctx.addr, rx.ctx.recv_dst, rx.seq); + return; + } + + /* Remove network headers */ + net_buf_simple_pull(&buf, BT_MESH_NET_HDR_LEN); + + BT_DBG("%u bytes: %s", buf.len, bt_hex(buf.data, buf.len)); + + if (buf.len < 1) { + BT_WARN("Too short proxy configuration PDU"); + return; + } + + proxy_filter_recv(role->conn, &rx, &buf); +} + +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"); + proxy_cfg(role); + break; + default: + BT_WARN("Unhandled Message Type 0x%02x", role->msg_type); + break; + } +} + static int beacon_send(struct bt_mesh_proxy_client *client, struct bt_mesh_subnet *sub) { @@ -334,7 +315,7 @@ static int beacon_send(struct bt_mesh_proxy_client *client, net_buf_simple_reserve(&buf, 1); bt_mesh_beacon_create(sub, &buf); - return bt_mesh_proxy_msg_send(&client->cli, BT_MESH_PROXY_BEACON, + return bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_BEACON, &buf, NULL, NULL); } @@ -365,7 +346,7 @@ void bt_mesh_proxy_beacon_send(struct bt_mesh_subnet *sub) } for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].cli.conn) { + if (clients[i].cli) { beacon_send(&clients[i], sub); } } @@ -661,10 +642,7 @@ static ssize_t proxy_ccc_write(struct bt_conn *conn, return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED); } - /* If a connection exists there must be a client */ client = find_client(conn); - __ASSERT(client, "No client for connection"); - if (client->filter_type == NONE) { client->filter_type = ACCEPT; k_work_submit(&client->send_beacons); @@ -701,19 +679,19 @@ int bt_mesh_proxy_gatt_enable(void) BT_DBG(""); - if (gatt_svc == MESH_GATT_PROXY) { - return -EALREADY; + if (!bt_mesh_is_provisioned()) { + return -ENOTSUP; } - if (gatt_svc != MESH_GATT_NONE) { + if (service_registered) { return -EBUSY; } (void)bt_gatt_service_register(&proxy_svc); - gatt_svc = MESH_GATT_PROXY; + service_registered = true; for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].cli.conn) { + if (clients[i].cli) { clients[i].filter_type = ACCEPT; } } @@ -730,10 +708,10 @@ void bt_mesh_proxy_gatt_disconnect(void) for (i = 0; i < ARRAY_SIZE(clients); i++) { struct bt_mesh_proxy_client *client = &clients[i]; - if (client->cli.conn && (client->filter_type == ACCEPT || + if (client->cli && (client->filter_type == ACCEPT || client->filter_type == REJECT)) { client->filter_type = NONE; - bt_conn_disconnect(client->cli.conn, + bt_conn_disconnect(client->cli->conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN); } } @@ -743,26 +721,25 @@ int bt_mesh_proxy_gatt_disable(void) { BT_DBG(""); - if (gatt_svc == MESH_GATT_NONE) { + if (!service_registered) { return -EALREADY; } - if (gatt_svc != MESH_GATT_PROXY) { - return -EBUSY; - } - bt_mesh_proxy_gatt_disconnect(); bt_gatt_service_unregister(&proxy_svc); - gatt_svc = MESH_GATT_NONE; + service_registered = false; return 0; } void bt_mesh_proxy_addr_add(struct net_buf_simple *buf, uint16_t addr) { - struct bt_mesh_proxy_client *client = - CONTAINER_OF(buf, struct bt_mesh_proxy_client, cli.buf); + struct bt_mesh_proxy_client *client; + struct bt_mesh_proxy_role *cli = + CONTAINER_OF(buf, struct bt_mesh_proxy_role, buf); + + client = find_client(cli->conn); BT_DBG("filter_type %u addr 0x%04x", client->filter_type, addr); @@ -824,7 +801,7 @@ bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst) NET_BUF_SIMPLE_DEFINE(msg, 32); - if (!client->cli.conn) { + if (!client->cli) { continue; } @@ -832,18 +809,13 @@ bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst) continue; } - if (client->filter_type == PROV) { - BT_ERR("Invalid PDU type for Proxy Client"); - return -EINVAL; - } - /* Proxy PDU sending modifies the original buffer, * so we need to make a copy. */ net_buf_simple_reserve(&msg, 1); net_buf_simple_add_mem(&msg, buf->data, buf->len); - err = bt_mesh_proxy_msg_send(&client->cli, BT_MESH_PROXY_NET_PDU, + err = bt_mesh_proxy_msg_send(client->cli, BT_MESH_PROXY_NET_PDU, &msg, buf_send_end, net_buf_ref(buf)); bt_mesh_adv_send_start(0, err, BT_MESH_ADV(buf)); @@ -864,7 +836,6 @@ bool bt_mesh_proxy_relay(struct net_buf *buf, uint16_t dst) return relayed; } -#endif /* CONFIG_BT_MESH_GATT_PROXY */ static void gatt_connected(struct bt_conn *conn, uint8_t err) { @@ -872,7 +843,8 @@ static void gatt_connected(struct bt_conn *conn, uint8_t err) struct bt_conn_info info; bt_conn_get_info(conn, &info); - if (info.role != BT_CONN_ROLE_PERIPHERAL) { + if (info.role != BT_CONN_ROLE_PERIPHERAL || + !service_registered) { return; } @@ -880,269 +852,50 @@ static void gatt_connected(struct bt_conn *conn, uint8_t err) conn_count++; + client = find_client(conn); + + client->filter_type = NONE; + (void)memset(client->filter, 0, sizeof(client->filter)); + client->cli = bt_mesh_proxy_role_setup(conn, proxy_send, + proxy_msg_recv); + /* Try to re-enable advertising in case it's possible */ if (conn_count < CONFIG_BT_MAX_CONN) { bt_mesh_adv_update(); } - - client = find_client(NULL); - if (!client) { - BT_ERR("No free Proxy Client objects"); - return; - } - - client->cli.conn = bt_conn_ref(conn); - client->filter_type = NONE; - (void)memset(client->filter, 0, sizeof(client->filter)); - net_buf_simple_reset(&client->cli.buf); } static void gatt_disconnected(struct bt_conn *conn, uint8_t reason) { - int i; struct bt_conn_info info; + struct bt_mesh_proxy_client *client; bt_conn_get_info(conn, &info); if (info.role != BT_CONN_ROLE_PERIPHERAL) { return; } - BT_DBG("conn %p reason 0x%02x", (void *)conn, reason); - - conn_count--; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if (client->cli.conn != conn) { - continue; - } - - if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT) && - client->filter_type == PROV) { - bt_mesh_pb_gatt_close(conn); - } - - /* If this fails, the work handler exits early, as - * there's no active connection. - */ - (void)k_work_cancel_delayable(&client->cli.sar_timer); - bt_conn_unref(client->cli.conn); - client->cli.conn = NULL; - break; + if (!service_registered && bt_mesh_is_provisioned()) { + (void)bt_mesh_proxy_gatt_enable(); + return; } - bt_mesh_adv_update(); -} - -struct net_buf_simple *bt_mesh_proxy_get_buf(void) -{ - struct net_buf_simple *buf = &clients[0].cli.buf; - - net_buf_simple_reset(buf); - - return buf; -} - -#if defined(CONFIG_BT_MESH_PB_GATT) -static void prov_ccc_changed(const struct bt_gatt_attr *attr, uint16_t value) -{ - BT_DBG("value 0x%04x", value); -} - -static ssize_t prov_ccc_write(struct bt_conn *conn, - const struct bt_gatt_attr *attr, uint16_t value) -{ - struct bt_mesh_proxy_client *client; - - BT_DBG("value 0x%04x", value); - - if (value != BT_GATT_CCC_NOTIFY) { - BT_WARN("Client wrote 0x%04x instead enabling notify", value); - return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED); - } + conn_count--; - /* If a connection exists there must be a client */ client = find_client(conn); - __ASSERT(client, "No client for connection"); - - if (client->filter_type == NONE) { - client->filter_type = PROV; - bt_mesh_pb_gatt_open(conn); - } - - return sizeof(value); + client->cli = NULL; } -/* Mesh Provisioning Service Declaration */ -static struct _bt_gatt_ccc prov_ccc = - BT_GATT_CCC_INITIALIZER(prov_ccc_changed, prov_ccc_write, NULL); - -static struct bt_gatt_attr prov_attrs[] = { - BT_GATT_PRIMARY_SERVICE(BT_UUID_MESH_PROV), - - BT_GATT_CHARACTERISTIC(BT_UUID_MESH_PROV_DATA_IN, - BT_GATT_CHRC_WRITE_WITHOUT_RESP, - BT_GATT_PERM_WRITE, NULL, gatt_recv, - (void *)1), - - BT_GATT_CHARACTERISTIC(BT_UUID_MESH_PROV_DATA_OUT, - BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_NONE, - NULL, NULL, NULL), - BT_GATT_CCC_MANAGED(&prov_ccc, - BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), -}; - -static struct bt_gatt_service prov_svc = BT_GATT_SERVICE(prov_attrs); - -int bt_mesh_proxy_prov_enable(void) -{ - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_PROV) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_NONE) { - return -EBUSY; - } - - (void)bt_gatt_service_register(&prov_svc); - gatt_svc = MESH_GATT_PROV; - prov_fast_adv = true; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - if (clients[i].cli.conn) { - clients[i].filter_type = PROV; - } - } - - - return 0; -} - -int bt_mesh_proxy_prov_disable(bool disconnect) -{ - int i; - - BT_DBG(""); - - if (gatt_svc == MESH_GATT_NONE) { - return -EALREADY; - } - - if (gatt_svc != MESH_GATT_PROV) { - return -EBUSY; - } - - bt_gatt_service_unregister(&prov_svc); - gatt_svc = MESH_GATT_NONE; - - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - if (!client->cli.conn || client->filter_type != PROV) { - continue; - } - - if (disconnect) { - bt_conn_disconnect(client->cli.conn, - BT_HCI_ERR_REMOTE_USER_TERM_CONN); - } else { - bt_mesh_pb_gatt_close(client->cli.conn); - client->filter_type = NONE; - } - } - - bt_mesh_adv_update(); - - return 0; -} -static uint8_t prov_svc_data[20] = { - BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL), -}; - -static const struct bt_data prov_ad[] = { - BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), - BT_DATA_BYTES(BT_DATA_UUID16_ALL, - BT_UUID_16_ENCODE(BT_UUID_MESH_PROV_VAL)), - BT_DATA(BT_DATA_SVC_DATA16, prov_svc_data, sizeof(prov_svc_data)), -}; - -int bt_mesh_pb_gatt_send(struct bt_conn *conn, struct net_buf_simple *buf, - bt_gatt_complete_func_t end, void *user_data) -{ - struct bt_mesh_proxy_client *client = find_client(conn); - - if (!client) { - BT_ERR("No Proxy Client found"); - return -ENOTCONN; - } - - if (client->filter_type != PROV) { - BT_ERR("Invalid PDU type for Proxy Client"); - return -EINVAL; - } - - return bt_mesh_proxy_msg_send(&client->cli, BT_MESH_PROXY_PROV, buf, end, user_data); -} - -static size_t gatt_prov_adv_create(struct bt_data prov_sd[1]) -{ - const struct bt_mesh_prov *prov = bt_mesh_prov_get(); - size_t uri_len; - - memcpy(prov_svc_data + 2, prov->uuid, 16); - sys_put_be16(prov->oob_info, prov_svc_data + 18); - - if (!prov->uri) { - return 0; - } - - uri_len = strlen(prov->uri); - if (uri_len > 29) { - /* There's no way to shorten an URI */ - BT_WARN("Too long URI to fit advertising packet"); - return 0; - } - - prov_sd[0].type = BT_DATA_URI; - prov_sd[0].data_len = uri_len; - prov_sd[0].data = (const uint8_t *)prov->uri; - - return 1; -} -#endif /* CONFIG_BT_MESH_PB_GATT */ - static int proxy_send(struct bt_conn *conn, const void *data, uint16_t len, bt_gatt_complete_func_t end, void *user_data) { - const struct bt_gatt_attr *attr = NULL; - BT_DBG("%u bytes: %s", len, bt_hex(data, len)); -#if defined(CONFIG_BT_MESH_GATT_PROXY) - if (gatt_svc == MESH_GATT_PROXY) { - attr = &proxy_attrs[3]; - } -#endif /* CONFIG_BT_MESH_GATT_PROXY */ -#if defined(CONFIG_BT_MESH_PB_GATT) - if (gatt_svc == MESH_GATT_PROV) { - attr = &prov_attrs[3]; - } -#endif /* CONFIG_BT_MESH_PB_GATT */ - - if (!attr) { - return -ENOENT; - } - struct bt_gatt_notify_params params = { .data = data, .len = len, - .attr = attr, + .attr = &proxy_attrs[3], .user_data = user_data, .func = end, }; @@ -1154,75 +907,14 @@ int bt_mesh_proxy_adv_start(void) { BT_DBG(""); - if (gatt_svc == MESH_GATT_NONE) { - return -ENOENT; + if (!service_registered || !bt_mesh_is_provisioned()) { + return -ENOTSUP; } -#if defined(CONFIG_BT_MESH_PB_GATT) - if (!bt_mesh_is_provisioned()) { - struct bt_le_adv_param fast_adv_param = { - .options = ADV_OPT_PROV, - ADV_FAST_INT, - }; - struct bt_data prov_sd[1]; - size_t prov_sd_len; - int err; - - prov_sd_len = gatt_prov_adv_create(prov_sd); - - if (!prov_fast_adv) { - struct bt_le_adv_param slow_adv_param = { - .options = ADV_OPT_PROV, - ADV_SLOW_INT, - }; - - return bt_mesh_adv_start(&slow_adv_param, - SYS_FOREVER_MS, prov_ad, - ARRAY_SIZE(prov_ad), prov_sd, - prov_sd_len); - } - - /* Advertise 60 seconds using fast interval */ - err = bt_mesh_adv_start(&fast_adv_param, (60 * MSEC_PER_SEC), - prov_ad, ARRAY_SIZE(prov_ad), - prov_sd, prov_sd_len); - if (!err) { - prov_fast_adv = false; - } - - return err; - } -#endif /* CONFIG_BT_MESH_PB_GATT */ - -#if defined(CONFIG_BT_MESH_GATT_PROXY) - if (bt_mesh_is_provisioned()) { - return gatt_proxy_advertise(next_sub()); - } -#endif /* CONFIG_BT_MESH_GATT_PROXY */ - - return -ENOTSUP; + return gatt_proxy_advertise(next_sub()); } -static struct bt_conn_cb conn_callbacks = { +BT_CONN_CB_DEFINE(conn_callbacks) = { .connected = gatt_connected, .disconnected = gatt_disconnected, }; - -int bt_mesh_proxy_init(void) -{ - int i; - - /* Initialize the client receive buffers */ - for (i = 0; i < ARRAY_SIZE(clients); i++) { - struct bt_mesh_proxy_client *client = &clients[i]; - - net_buf_simple_init_with_data(&client->cli.buf, - client_buf_data + (i * CLIENT_BUF_SIZE), CLIENT_BUF_SIZE); - - bt_mesh_proxy_msg_init(&client->cli); - } - - bt_conn_cb_register(&conn_callbacks); - - return 0; -} diff --git a/subsys/bluetooth/mesh/settings.c b/subsys/bluetooth/mesh/settings.c index 241f9376f48de..33f1e0703cbe3 100644 --- a/subsys/bluetooth/mesh/settings.c +++ b/subsys/bluetooth/mesh/settings.c @@ -26,6 +26,7 @@ #include "heartbeat.h" #include "access.h" #include "proxy.h" +#include "pb_gatt_srv.h" #include "settings.h" #include "cfg.h" @@ -61,7 +62,7 @@ static int mesh_commit(void) } if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT)) { - bt_mesh_proxy_prov_disable(true); + (void)bt_mesh_pb_gatt_disable(); } bt_mesh_net_settings_commit();