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