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