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 <bluetooth/mesh.h>
8 #include <bluetooth/conn.h>
9 #include "net.h"
10 #include "proxy.h"
11 #include "adv.h"
12 #include "host/ecc.h"
13 #include "prov.h"
14 
15 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_MESH_DEBUG_PROV)
16 #define LOG_MODULE_NAME bt_mesh_pb_gatt
17 #include "common/log.h"
18 
19 struct prov_bearer_send_cb {
20 	prov_bearer_send_complete_t cb;
21 	void *cb_data;
22 };
23 
24 struct prov_link {
25 	struct bt_conn *conn;
26 	const struct prov_bearer_cb *cb;
27 	void *cb_data;
28 	struct prov_bearer_send_cb comp;
29 	struct net_buf_simple *rx_buf;
30 	struct k_work_delayable prot_timer;
31 };
32 
33 static struct prov_link link;
34 
reset_state(void)35 static void reset_state(void)
36 {
37 	if (link.conn) {
38 		bt_conn_unref(link.conn);
39 		link.conn = NULL;
40 	}
41 
42 	/* If this fails, the protocol timeout handler will exit early. */
43 	(void)k_work_cancel_delayable(&link.prot_timer);
44 
45 	link.rx_buf = bt_mesh_proxy_get_buf();
46 }
47 
link_closed(enum prov_bearer_link_status status)48 static void link_closed(enum prov_bearer_link_status status)
49 {
50 	const struct prov_bearer_cb *cb = link.cb;
51 	void *cb_data = link.cb_data;
52 
53 	reset_state();
54 
55 	cb->link_closed(&pb_gatt, cb_data, status);
56 }
57 
protocol_timeout(struct k_work * work)58 static void protocol_timeout(struct k_work *work)
59 {
60 	if (!link.conn) {
61 		/* Already disconnected */
62 		return;
63 	}
64 
65 	BT_DBG("Protocol timeout");
66 	link_closed(PROV_BEARER_LINK_STATUS_TIMEOUT);
67 }
68 
bt_mesh_pb_gatt_recv(struct bt_conn * conn,struct net_buf_simple * buf)69 int bt_mesh_pb_gatt_recv(struct bt_conn *conn, struct net_buf_simple *buf)
70 {
71 	BT_DBG("%u bytes: %s", buf->len, bt_hex(buf->data, buf->len));
72 
73 	if (link.conn != conn || !link.cb) {
74 		BT_WARN("Data for unexpected connection");
75 		return -ENOTCONN;
76 	}
77 
78 	if (buf->len < 1) {
79 		BT_WARN("Too short provisioning packet (len %u)", buf->len);
80 		return -EINVAL;
81 	}
82 
83 	k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
84 
85 	link.cb->recv(&pb_gatt, link.cb_data, buf);
86 
87 	return 0;
88 }
89 
bt_mesh_pb_gatt_open(struct bt_conn * conn)90 int bt_mesh_pb_gatt_open(struct bt_conn *conn)
91 {
92 	BT_DBG("conn %p", (void *)conn);
93 
94 	if (link.conn) {
95 		return -EBUSY;
96 	}
97 
98 	link.conn = bt_conn_ref(conn);
99 	k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
100 
101 	link.cb->link_opened(&pb_gatt, link.cb_data);
102 
103 	return 0;
104 }
105 
bt_mesh_pb_gatt_close(struct bt_conn * conn)106 int bt_mesh_pb_gatt_close(struct bt_conn *conn)
107 {
108 	BT_DBG("conn %p", (void *)conn);
109 
110 	if (link.conn != conn) {
111 		BT_DBG("Not connected");
112 		return -ENOTCONN;
113 	}
114 
115 	link_closed(PROV_BEARER_LINK_STATUS_SUCCESS);
116 
117 	return 0;
118 }
119 
link_accept(const struct prov_bearer_cb * cb,void * cb_data)120 static int link_accept(const struct prov_bearer_cb *cb, void *cb_data)
121 {
122 	int err;
123 
124 	err = bt_mesh_adv_enable();
125 	if (err) {
126 		BT_ERR("Failed enabling advertiser");
127 		return err;
128 	}
129 
130 	(void)bt_mesh_proxy_prov_enable();
131 	bt_mesh_adv_update();
132 
133 	link.cb = cb;
134 	link.cb_data = cb_data;
135 
136 	return 0;
137 }
138 
buf_send_end(struct bt_conn * conn,void * user_data)139 static void buf_send_end(struct bt_conn *conn, void *user_data)
140 {
141 	if (link.comp.cb) {
142 		link.comp.cb(0, link.comp.cb_data);
143 	}
144 }
145 
buf_send(struct net_buf_simple * buf,prov_bearer_send_complete_t cb,void * cb_data)146 static int buf_send(struct net_buf_simple *buf, prov_bearer_send_complete_t cb,
147 		    void *cb_data)
148 {
149 	if (!link.conn) {
150 		return -ENOTCONN;
151 	}
152 
153 	link.comp.cb = cb;
154 	link.comp.cb_data = cb_data;
155 
156 	k_work_reschedule(&link.prot_timer, PROTOCOL_TIMEOUT);
157 
158 	return bt_mesh_pb_gatt_send(link.conn, buf, buf_send_end, NULL);
159 }
160 
clear_tx(void)161 static void clear_tx(void)
162 {
163 	/* No action */
164 }
165 
pb_gatt_init(void)166 void pb_gatt_init(void)
167 {
168 	k_work_init_delayable(&link.prot_timer, protocol_timeout);
169 }
170 
pb_gatt_reset(void)171 void pb_gatt_reset(void)
172 {
173 	reset_state();
174 }
175 
176 const struct prov_bearer pb_gatt = {
177 	.type = BT_MESH_PROV_GATT,
178 	.link_accept = link_accept,
179 	.send = buf_send,
180 	.clear_tx = clear_tx,
181 };
182