1 /*
2  * Copyright (c) 2017 Intel Corporation
3  * Copyright (c) 2020 Nordic Semiconductor ASA
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 #include <zephyr/bluetooth/mesh.h>
8 #include <zephyr/bluetooth/conn.h>
9 #include "net.h"
10 #include "proxy.h"
11 #include "prov.h"
12 #include "pb_gatt.h"
13 #include "proxy_msg.h"
14 #include "pb_gatt_srv.h"
15 #include "pb_gatt_cli.h"
16 
17 #include <zephyr/bluetooth/hci.h>
18 
19 #include "common/bt_str.h"
20 
21 #define LOG_LEVEL CONFIG_BT_MESH_PROV_LOG_LEVEL
22 #include <zephyr/logging/log.h>
23 LOG_MODULE_REGISTER(bt_mesh_pb_gatt);
24 
25 struct prov_bearer_send_cb {
26 	prov_bearer_send_complete_t cb;
27 	void *cb_data;
28 };
29 
30 struct prov_link {
31 	struct bt_conn *conn;
32 	const struct prov_bearer_cb *cb;
33 	void *cb_data;
34 	struct prov_bearer_send_cb comp;
35 	struct k_work_delayable prot_timer;
36 };
37 
38 static struct prov_link link;
39 
reset_state(void)40 static void reset_state(void)
41 {
42 	if (link.conn) {
43 		bt_conn_unref(link.conn);
44 		link.conn = NULL;
45 	}
46 
47 	/* If this fails, the protocol timeout handler will exit early. */
48 	(void)k_work_cancel_delayable(&link.prot_timer);
49 }
50 
link_closed(enum prov_bearer_link_status status)51 static void link_closed(enum prov_bearer_link_status status)
52 {
53 	const struct prov_bearer_cb *cb = link.cb;
54 	void *cb_data = link.cb_data;
55 
56 	reset_state();
57 
58 	cb->link_closed(&bt_mesh_pb_gatt, cb_data, status);
59 }
60 
protocol_timeout(struct k_work * work)61 static void protocol_timeout(struct k_work *work)
62 {
63 	if (!atomic_test_bit(bt_mesh_prov_link.flags, LINK_ACTIVE)) {
64 		return;
65 	}
66 
67 	/* If connection failed or timeout, not allow establish connection */
68 	if (IS_ENABLED(CONFIG_BT_MESH_PB_GATT_CLIENT) &&
69 	    atomic_test_bit(bt_mesh_prov_link.flags, PROVISIONER)) {
70 		if (link.conn) {
71 			(void)bt_conn_disconnect(link.conn,
72 						 BT_HCI_ERR_REMOTE_USER_TERM_CONN);
73 		} else {
74 			(void)bt_mesh_pb_gatt_cli_setup(NULL);
75 		}
76 	}
77 
78 	LOG_DBG("Protocol timeout");
79 
80 	link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT);
81 }
82 
bt_mesh_pb_gatt_recv(struct bt_conn * conn,struct net_buf_simple * buf)83 int bt_mesh_pb_gatt_recv(struct bt_conn *conn, struct net_buf_simple *buf)
84 {
85 	LOG_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len));
86 
87 	if (link.conn != conn || !link.cb) {
88 		LOG_WRN("Data for unexpected connection");
89 		return -ENOTCONN;
90 	}
91 
92 	if (buf->len < 1) {
93 		LOG_WRN("Too short provisioning packet (len %u)", buf->len);
94 		return -EINVAL;
95 	}
96 
97 	k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get());
98 
99 	link.cb->recv(&bt_mesh_pb_gatt, link.cb_data, buf);
100 
101 	return 0;
102 }
103 
bt_mesh_pb_gatt_start(struct bt_conn * conn)104 int bt_mesh_pb_gatt_start(struct bt_conn *conn)
105 {
106 	LOG_DBG("conn %p", (void *)conn);
107 
108 	if (link.conn) {
109 		return -EBUSY;
110 	}
111 
112 	link.conn = bt_conn_ref(conn);
113 	k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get());
114 
115 	link.cb->link_opened(&bt_mesh_pb_gatt, link.cb_data);
116 
117 	return 0;
118 }
119 
bt_mesh_pb_gatt_close(struct bt_conn * conn)120 int bt_mesh_pb_gatt_close(struct bt_conn *conn)
121 {
122 	LOG_DBG("conn %p", (void *)conn);
123 
124 	if (link.conn != conn) {
125 		LOG_DBG("Not connected");
126 		return -ENOTCONN;
127 	}
128 
129 	link_closed(PROV_BEARER_LINK_STATUS_SUCCESS);
130 
131 	return 0;
132 }
133 
134 #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
bt_mesh_pb_gatt_cli_start(struct bt_conn * conn)135 int bt_mesh_pb_gatt_cli_start(struct bt_conn *conn)
136 {
137 	LOG_DBG("conn %p", (void *)conn);
138 
139 	if (link.conn) {
140 		return -EBUSY;
141 	}
142 
143 	link.conn = bt_conn_ref(conn);
144 	k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get());
145 
146 	return 0;
147 }
148 
bt_mesh_pb_gatt_cli_open(struct bt_conn * conn)149 int bt_mesh_pb_gatt_cli_open(struct bt_conn *conn)
150 {
151 	LOG_DBG("conn %p", (void *)conn);
152 
153 	if (link.conn != conn) {
154 		LOG_DBG("Not connected");
155 		return -ENOTCONN;
156 	}
157 
158 	link.cb->link_opened(&bt_mesh_pb_gatt, link.cb_data);
159 
160 	return 0;
161 }
162 
prov_link_open(const uint8_t uuid[16],uint8_t timeout,const struct prov_bearer_cb * cb,void * cb_data)163 static int prov_link_open(const uint8_t uuid[16], uint8_t timeout,
164 			  const struct prov_bearer_cb *cb, void *cb_data)
165 {
166 	LOG_DBG("uuid %s", bt_hex(uuid, 16));
167 
168 	link.cb = cb;
169 	link.cb_data = cb_data;
170 
171 	k_work_reschedule(&link.prot_timer, K_SECONDS(timeout));
172 
173 	return bt_mesh_pb_gatt_cli_setup(uuid);
174 }
175 
prov_link_close(enum prov_bearer_link_status status)176 static void prov_link_close(enum prov_bearer_link_status status)
177 {
178 	(void)bt_conn_disconnect(link.conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
179 }
180 #endif
181 
182 #if defined(CONFIG_BT_MESH_PB_GATT)
link_accept(const struct prov_bearer_cb * cb,void * cb_data)183 static int link_accept(const struct prov_bearer_cb *cb, void *cb_data)
184 {
185 	int err;
186 
187 	err = bt_mesh_adv_enable();
188 	if (err) {
189 		LOG_ERR("Failed enabling advertiser");
190 		return err;
191 	}
192 
193 	(void)bt_mesh_pb_gatt_srv_enable();
194 	bt_mesh_adv_gatt_update();
195 
196 	link.cb = cb;
197 	link.cb_data = cb_data;
198 
199 	return 0;
200 }
201 #endif
202 
buf_send_end(struct bt_conn * conn,void * user_data)203 static void buf_send_end(struct bt_conn *conn, void *user_data)
204 {
205 	if (link.comp.cb) {
206 		link.comp.cb(0, link.comp.cb_data);
207 	}
208 }
209 
buf_send(struct net_buf_simple * buf,prov_bearer_send_complete_t cb,void * cb_data)210 static int buf_send(struct net_buf_simple *buf, prov_bearer_send_complete_t cb,
211 		    void *cb_data)
212 {
213 	if (!link.conn) {
214 		return -ENOTCONN;
215 	}
216 
217 	link.comp.cb = cb;
218 	link.comp.cb_data = cb_data;
219 
220 	k_work_reschedule(&link.prot_timer, bt_mesh_prov_protocol_timeout_get());
221 
222 	return bt_mesh_proxy_msg_send(link.conn, BT_MESH_PROXY_PROV,
223 				      buf, buf_send_end, NULL);
224 }
225 
clear_tx(void)226 static void clear_tx(void)
227 {
228 	/* No action */
229 }
230 
bt_mesh_pb_gatt_init(void)231 void bt_mesh_pb_gatt_init(void)
232 {
233 	k_work_init_delayable(&link.prot_timer, protocol_timeout);
234 }
235 
bt_mesh_pb_gatt_reset(void)236 void bt_mesh_pb_gatt_reset(void)
237 {
238 	reset_state();
239 }
240 
241 const struct prov_bearer bt_mesh_pb_gatt = {
242 	.type = BT_MESH_PROV_GATT,
243 #if defined(CONFIG_BT_MESH_PB_GATT_CLIENT)
244 	.link_open = prov_link_open,
245 	.link_close = prov_link_close,
246 #endif
247 #if defined(CONFIG_BT_MESH_PB_GATT)
248 	.link_accept = link_accept,
249 #endif
250 	.send = buf_send,
251 	.clear_tx = clear_tx,
252 };
253