Bluetooth: Mesh: Add Provisioner Over PB-GATT Support

Add support provisioner over pb-gatt.

Signed-off-by: Lingao Meng <menglingao@xiaomi.com>
diff --git a/include/bluetooth/mesh/main.h b/include/bluetooth/mesh/main.h
index 71fccd8..7ffba08 100644
--- a/include/bluetooth/mesh/main.h
+++ b/include/bluetooth/mesh/main.h
@@ -213,6 +213,17 @@
 					    bt_mesh_prov_oob_info_t oob_info,
 					    uint32_t *uri_hash);
 
+	/** @brief PB-GATT Unprovisioned Advertising has been received.
+	 *
+	 *  This callback notifies the application that an PB-GATT
+	 *  unprovisioned Advertising has been received.
+	 *
+	 *  @param uuid     UUID
+	 *  @param oob_info OOB Information
+	 */
+	void        (*unprovisioned_beacon_gatt)(uint8_t uuid[16],
+						 bt_mesh_prov_oob_info_t oob_info);
+
 	/** @brief Provisioning link has been opened.
 	 *
 	 *  This callback notifies the application that a provisioning
@@ -424,6 +435,19 @@
 int bt_mesh_provision_adv(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
 			  uint8_t attention_duration);
 
+/** @brief Provision a Mesh Node using PB-GATT
+ *
+ *  @param uuid               UUID
+ *  @param net_idx            Network Key Index
+ *  @param addr               Address to assign to remote device. If addr is 0,
+ *                            the lowest available address will be chosen.
+ *  @param attention_duration The attention duration to be send to remote device
+ *
+ *  @return Zero on success or (negative) error code otherwise.
+ */
+int bt_mesh_provision_gatt(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
+			   uint8_t attention_duration);
+
 /** @brief Check if the local node has been provisioned.
  *
  *  This API can be used to check if the local node has been provisioned
diff --git a/subsys/bluetooth/mesh/CMakeLists.txt b/subsys/bluetooth/mesh/CMakeLists.txt
index d6f0baf..3b0ff51 100644
--- a/subsys/bluetooth/mesh/CMakeLists.txt
+++ b/subsys/bluetooth/mesh/CMakeLists.txt
@@ -39,10 +39,9 @@
 
 zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_ADV pb_adv.c)
 
-zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_GATT
-    pb_gatt.c
-    pb_gatt_srv.c
-)
+zephyr_library_sources_ifdef(CONFIG_BT_MESH_PB_GATT_COMMON pb_gatt.c)
+
+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)
 
diff --git a/subsys/bluetooth/mesh/Kconfig b/subsys/bluetooth/mesh/Kconfig
index 522bc5f..63443af 100644
--- a/subsys/bluetooth/mesh/Kconfig
+++ b/subsys/bluetooth/mesh/Kconfig
@@ -62,7 +62,7 @@
 config BT_MESH_PROVISIONER
 	bool "Provisioner support"
 	depends on BT_MESH_PROV
-	depends on BT_MESH_PB_ADV
+	depends on BT_MESH_PB_ADV || BT_MESH_PB_GATT_CLIENT
 	help
 	  Enable this option to have support for provisioning remote devices.
 
@@ -123,10 +123,26 @@
 	select BT_MESH_GATT
 	select BT_GATT_DYNAMIC_DB
 
+config BT_MESH_PB_GATT_COMMON
+	bool
+
+config BT_MESH_PB_GATT_CLIENT
+	bool "Provisioner support using GATT (PB-GATT)"
+	select BT_MESH_PROV
+	select BT_GATT_CLIENT
+	select BT_MESH_GATT_CLIENT
+	select BT_MESH_PB_GATT_COMMON
+	select BT_MESH_PROVISIONER
+	depends on BT_CENTRAL
+	help
+	  Enable this option to allow the provisioner provisioning the
+	  device over GATT.
+
 config BT_MESH_PB_GATT
 	bool "Provisioning support using GATT (PB-GATT)"
 	select BT_MESH_GATT_SERVER
 	select BT_MESH_PROV
+	select BT_MESH_PB_GATT_COMMON
 	help
 	  Enable this option to allow the device to be provisioned over
 	  GATT.
diff --git a/subsys/bluetooth/mesh/gatt_cli.c b/subsys/bluetooth/mesh/gatt_cli.c
index 02c4e1d..1bc06e9 100644
--- a/subsys/bluetooth/mesh/gatt_cli.c
+++ b/subsys/bluetooth/mesh/gatt_cli.c
@@ -33,6 +33,7 @@
 #include "proxy_msg.h"
 #include "proxy_cli.h"
 #include "gatt_cli.h"
+#include "pb_gatt_cli.h"
 
 static struct bt_mesh_gatt_server {
 	struct bt_conn *conn;
@@ -282,6 +283,11 @@
 		bt_mesh_proxy_cli_adv_recv(info, buf);
 		break;
 #endif
+#if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
+	case BT_UUID_MESH_PROV_VAL:
+		bt_mesh_pb_gatt_cli_adv_recv(info, buf);
+		break;
+#endif
 
 	default:
 		break;
diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c
index dfe850f..05fb793 100644
--- a/subsys/bluetooth/mesh/main.c
+++ b/subsys/bluetooth/mesh/main.c
@@ -142,6 +142,25 @@
 	return -ENOTSUP;
 }
 
+int bt_mesh_provision_gatt(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
+			   uint8_t attention_duration)
+{
+	if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
+		return -EINVAL;
+	}
+
+	if (bt_mesh_subnet_get(net_idx) == NULL) {
+		return -EINVAL;
+	}
+
+	if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT_CLIENT)) {
+		return bt_mesh_pb_gatt_open(uuid, net_idx, addr,
+					    attention_duration);
+	}
+
+	return -ENOTSUP;
+}
+
 void bt_mesh_reset(void)
 {
 	if (!atomic_test_bit(bt_mesh.flags, BT_MESH_VALID)) {
diff --git a/subsys/bluetooth/mesh/pb_gatt.c b/subsys/bluetooth/mesh/pb_gatt.c
index 83e1fe6..1d83d2d 100644
--- a/subsys/bluetooth/mesh/pb_gatt.c
+++ b/subsys/bluetooth/mesh/pb_gatt.c
@@ -14,6 +14,7 @@
 #include "pb_gatt.h"
 #include "proxy_msg.h"
 #include "pb_gatt_srv.h"
+#include "pb_gatt_cli.h"
 
 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_PROV)
 #define LOG_MODULE_NAME bt_mesh_pb_gatt
@@ -57,12 +58,23 @@
 
 static void protocol_timeout(struct k_work *work)
 {
-	if (!link.conn) {
-		/* Already disconnected */
+	if (!atomic_test_bit(bt_mesh_prov_link.flags, LINK_ACTIVE)) {
 		return;
 	}
 
+	/* If connection failed or timeout, not allow establish connection */
+	if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT_CLIENT) &&
+	    atomic_test_bit(bt_mesh_prov_link.flags, PROVISIONER)) {
+		if (link.conn) {
+			(void)bt_conn_disconnect(link.conn,
+						 BT_HCI_ERR_REMOTE_USER_TERM_CONN);
+		} else {
+			(void)bt_mesh_pb_gatt_cli_setup(NULL);
+		}
+	}
+
 	BT_DBG("Protocol timeout");
+
 	link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT);
 }
 
@@ -87,7 +99,7 @@
 	return 0;
 }
 
-int bt_mesh_pb_gatt_open(struct bt_conn *conn)
+int bt_mesh_pb_gatt_start(struct bt_conn *conn)
 {
 	BT_DBG("conn %p", (void *)conn);
 
@@ -117,6 +129,55 @@
 	return 0;
 }
 
+#if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
+int bt_mesh_pb_gatt_cli_start(struct bt_conn *conn)
+{
+	BT_DBG("conn %p", (void *)conn);
+
+	if (link.conn) {
+		return -EBUSY;
+	}
+
+	link.conn = bt_conn_ref(conn);
+	k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
+
+	return 0;
+}
+
+int bt_mesh_pb_gatt_cli_open(struct bt_conn *conn)
+{
+	BT_DBG("conn %p", (void *)conn);
+
+	if (link.conn != conn) {
+		BT_DBG("Not connected");
+		return -ENOTCONN;
+	}
+
+	link.cb->link_opened(&pb_gatt, link.cb_data);
+
+	return 0;
+}
+
+static int prov_link_open(const uint8_t uuid[16], k_timeout_t timeout,
+			  const struct prov_bearer_cb *cb, void *cb_data)
+{
+	BT_DBG("uuid %s", bt_hex(uuid, 16));
+
+	link.cb = cb;
+	link.cb_data = cb_data;
+
+	k_work_reschedule(&link.prot_timer, timeout);
+
+	return bt_mesh_pb_gatt_cli_setup(uuid);
+}
+
+static void prov_link_close(enum prov_bearer_link_status status)
+{
+	(void)bt_conn_disconnect(link.conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
+}
+#endif
+
+#if defined(CONFIG_BT_MESH_PB_GATT)
 static int link_accept(const struct prov_bearer_cb *cb, void *cb_data)
 {
 	int err;
@@ -135,6 +196,7 @@
 
 	return 0;
 }
+#endif
 
 static void buf_send_end(struct bt_conn *conn, void *user_data)
 {
@@ -155,7 +217,8 @@
 
 	k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
 
-	return bt_mesh_pb_gatt_send(link.conn, buf, buf_send_end, NULL);
+	return bt_mesh_proxy_msg_send(link.conn, BT_MESH_PROXY_PROV,
+				      buf, buf_send_end, NULL);
 }
 
 static void clear_tx(void)
@@ -175,7 +238,13 @@
 
 const struct prov_bearer pb_gatt = {
 	.type = BT_MESH_PROV_GATT,
+#if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
+	.link_open = prov_link_open,
+	.link_close = prov_link_close,
+#endif
+#if defined(CONFIG_BT_MESH_PB_GATT)
 	.link_accept = link_accept,
+#endif
 	.send = buf_send,
 	.clear_tx = clear_tx,
 };
diff --git a/subsys/bluetooth/mesh/pb_gatt.h b/subsys/bluetooth/mesh/pb_gatt.h
index 6b9d7de..68e0652 100644
--- a/subsys/bluetooth/mesh/pb_gatt.h
+++ b/subsys/bluetooth/mesh/pb_gatt.h
@@ -9,3 +9,6 @@
 int bt_mesh_pb_gatt_start(struct bt_conn *conn);
 int bt_mesh_pb_gatt_close(struct bt_conn *conn);
 int bt_mesh_pb_gatt_recv(struct bt_conn *conn, struct net_buf_simple *buf);
+
+int bt_mesh_pb_gatt_cli_open(struct bt_conn *conn);
+int bt_mesh_pb_gatt_cli_start(struct bt_conn *conn);
diff --git a/subsys/bluetooth/mesh/pb_gatt_cli.c b/subsys/bluetooth/mesh/pb_gatt_cli.c
index 60e9a40..9329560 100644
--- a/subsys/bluetooth/mesh/pb_gatt_cli.c
+++ b/subsys/bluetooth/mesh/pb_gatt_cli.c
@@ -58,11 +58,13 @@
 					      pb_gatt_msg_recv);
 
 	server.target = NULL;
+
+	bt_mesh_pb_gatt_cli_start(conn);
 }
 
 static void pb_gatt_link_open(struct bt_conn *conn)
 {
-	bt_mesh_pb_gatt_start(conn);
+	bt_mesh_pb_gatt_cli_open(conn);
 }
 
 static void pb_gatt_disconnected(struct bt_conn *conn)
diff --git a/subsys/bluetooth/mesh/pb_gatt_cli.h b/subsys/bluetooth/mesh/pb_gatt_cli.h
new file mode 100644
index 0000000..6ec0b52
--- /dev/null
+++ b/subsys/bluetooth/mesh/pb_gatt_cli.h
@@ -0,0 +1,11 @@
+/*
+ * Copyright (c) 2021 Xiaomi Corporation
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+
+int bt_mesh_pb_gatt_cli_setup(const uint8_t uuid[16]);
+
+void bt_mesh_pb_gatt_cli_adv_recv(const struct bt_le_scan_recv_info *info,
+				  struct net_buf_simple *buf);
diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.c b/subsys/bluetooth/mesh/pb_gatt_srv.c
index 5f2489e..cb67279 100644
--- a/subsys/bluetooth/mesh/pb_gatt_srv.c
+++ b/subsys/bluetooth/mesh/pb_gatt_srv.c
@@ -148,7 +148,7 @@
 		return BT_GATT_ERR(BT_ATT_ERR_VALUE_NOT_ALLOWED);
 	}
 
-	bt_mesh_pb_gatt_open(conn);
+	bt_mesh_pb_gatt_start(conn);
 
 	return sizeof(value);
 }
@@ -220,17 +220,6 @@
 	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(conn, 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();
diff --git a/subsys/bluetooth/mesh/pb_gatt_srv.h b/subsys/bluetooth/mesh/pb_gatt_srv.h
index 105f7b9..24a2306 100644
--- a/subsys/bluetooth/mesh/pb_gatt_srv.h
+++ b/subsys/bluetooth/mesh/pb_gatt_srv.h
@@ -10,9 +10,6 @@
 
 #include <bluetooth/gatt.h>
 
-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);
 
diff --git a/subsys/bluetooth/mesh/provisioner.c b/subsys/bluetooth/mesh/provisioner.c
index e5b5fe5..e1c947a 100644
--- a/subsys/bluetooth/mesh/provisioner.c
+++ b/subsys/bluetooth/mesh/provisioner.c
@@ -726,9 +726,10 @@
 	return 0;
 }
 
-#if defined(CONFIG_BT_MESH_PB_ADV)
-int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
-			uint8_t attention_duration)
+static int bt_mesh_provisioner_open(const struct prov_bearer *bearer,
+				    const uint8_t uuid[16],
+				    uint16_t net_idx, uint16_t addr,
+				    uint8_t attention_duration)
 {
 	int err;
 
@@ -746,7 +747,7 @@
 	prov_device.addr = addr;
 	prov_device.net_idx = net_idx;
 	prov_device.attention_duration = attention_duration;
-	bt_mesh_prov_link.bearer = &pb_adv;
+	bt_mesh_prov_link.bearer = bearer;
 	bt_mesh_prov_link.role = &role_provisioner;
 
 	err = bt_mesh_prov_link.bearer->link_open(prov_device.uuid, PROTOCOL_TIMEOUT,
@@ -757,4 +758,19 @@
 
 	return err;
 }
+
+#if defined(CONFIG_BT_MESH_PB_ADV)
+int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
+			uint8_t attention_duration)
+{
+	return bt_mesh_provisioner_open(&pb_adv, uuid, net_idx, addr, attention_duration);
+}
+#endif
+
+#if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
+int bt_mesh_pb_gatt_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
+			 uint8_t attention_duration)
+{
+	return bt_mesh_provisioner_open(&pb_gatt, uuid, net_idx, addr, attention_duration);
+}
 #endif
diff --git a/subsys/bluetooth/mesh/provisioner.h b/subsys/bluetooth/mesh/provisioner.h
index ac58ab3..0745ff3 100644
--- a/subsys/bluetooth/mesh/provisioner.h
+++ b/subsys/bluetooth/mesh/provisioner.h
@@ -7,3 +7,6 @@
 
 int bt_mesh_pb_adv_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
 			uint8_t attention_duration);
+
+int bt_mesh_pb_gatt_open(const uint8_t uuid[16], uint16_t net_idx, uint16_t addr,
+			 uint8_t attention_duration);