1 // Copyright 2017-2019 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <string.h>
16 #include <errno.h>
17
18 #include "mesh.h"
19 #include "mesh_main.h"
20 #include "transport.h"
21 #include "foundation.h"
22 #include "client_common.h"
23 #include "mesh_common.h"
24
25 #define HCI_TIME_FOR_START_ADV K_MSEC(5) /* Three adv related hci commands may take 4 ~ 5ms */
26
bt_mesh_client_pick_node(sys_slist_t * list,uint16_t tx_dst)27 static bt_mesh_client_node_t *bt_mesh_client_pick_node(sys_slist_t *list, uint16_t tx_dst)
28 {
29 bt_mesh_client_node_t *node = NULL;
30 sys_snode_t *cur = NULL;
31
32 bt_mesh_list_lock();
33 if (sys_slist_is_empty(list)) {
34 bt_mesh_list_unlock();
35 return NULL;
36 }
37
38 for (cur = sys_slist_peek_head(list);
39 cur != NULL; cur = sys_slist_peek_next(cur)) {
40 node = (bt_mesh_client_node_t *)cur;
41 if (node->ctx.addr == tx_dst) {
42 bt_mesh_list_unlock();
43 return node;
44 }
45 }
46
47 bt_mesh_list_unlock();
48 return NULL;
49 }
50
bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model * model,struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * buf,bool need_pub)51 bt_mesh_client_node_t *bt_mesh_is_client_recv_publish_msg(struct bt_mesh_model *model,
52 struct bt_mesh_msg_ctx *ctx,
53 struct net_buf_simple *buf, bool need_pub)
54 {
55 bt_mesh_client_internal_data_t *data = NULL;
56 bt_mesh_client_user_data_t *cli = NULL;
57 bt_mesh_client_node_t *node = NULL;
58
59 if (!model || !ctx || !buf) {
60 BT_ERR("%s, Invalid parameter", __func__);
61 return NULL;
62 }
63
64 cli = (bt_mesh_client_user_data_t *)model->user_data;
65 if (!cli) {
66 BT_ERR("Invalid client user data");
67 return NULL;
68 }
69
70 /** If the received message address is not a unicast address,
71 * the address may be a group/virtual address, and we push
72 * this message to the application layer.
73 */
74 if (!BLE_MESH_ADDR_IS_UNICAST(ctx->recv_dst)) {
75 BT_DBG("Unexpected status message 0x%08x", ctx->recv_op);
76 if (cli->publish_status && need_pub) {
77 cli->publish_status(ctx->recv_op, model, ctx, buf);
78 }
79 return NULL;
80 }
81
82 /** If the source address of the received status message is
83 * different with the destination address of the sending
84 * message, then the message is from another element and
85 * push it to application layer.
86 */
87 data = (bt_mesh_client_internal_data_t *)cli->internal_data;
88 if (!data) {
89 BT_ERR("Invalid client internal data");
90 return NULL;
91 }
92
93 if ((node = bt_mesh_client_pick_node(&data->queue, ctx->addr)) == NULL) {
94 BT_DBG("Unexpected status message 0x%08x", ctx->recv_op);
95 if (cli->publish_status && need_pub) {
96 cli->publish_status(ctx->recv_op, model, ctx, buf);
97 }
98 return NULL;
99 }
100
101 if (node->op_pending != ctx->recv_op) {
102 BT_DBG("Unexpected status message 0x%08x", ctx->recv_op);
103 if (cli->publish_status && need_pub) {
104 cli->publish_status(ctx->recv_op, model, ctx, buf);
105 }
106 return NULL;
107 }
108
109 if (k_delayed_work_remaining_get(&node->timer) == 0) {
110 BT_DBG("Unexpected status message 0x%08x", ctx->recv_op);
111 if (cli->publish_status && need_pub) {
112 cli->publish_status(ctx->recv_op, model, ctx, buf);
113 }
114 return NULL;
115 }
116
117 return node;
118 }
119
bt_mesh_client_check_node_in_list(sys_slist_t * list,uint16_t tx_dst)120 static bool bt_mesh_client_check_node_in_list(sys_slist_t *list, uint16_t tx_dst)
121 {
122 bt_mesh_client_node_t *node = NULL;
123 sys_snode_t *cur = NULL;
124
125 bt_mesh_list_lock();
126 if (sys_slist_is_empty(list)) {
127 bt_mesh_list_unlock();
128 return false;
129 }
130
131 for (cur = sys_slist_peek_head(list);
132 cur != NULL; cur = sys_slist_peek_next(cur)) {
133 node = (bt_mesh_client_node_t *)cur;
134 if (node->ctx.addr == tx_dst) {
135 bt_mesh_list_unlock();
136 return true;
137 }
138 }
139
140 bt_mesh_list_unlock();
141 return false;
142 }
143
bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t * op_pair,int size,uint32_t opcode)144 static uint32_t bt_mesh_client_get_status_op(const bt_mesh_client_op_pair_t *op_pair,
145 int size, uint32_t opcode)
146 {
147 if (!op_pair || size == 0) {
148 return 0;
149 }
150
151 const bt_mesh_client_op_pair_t *op = op_pair;
152 for (int i = 0; i < size; i++) {
153 if (op->cli_op == opcode) {
154 return op->status_op;
155 }
156 op++;
157 }
158
159 return 0;
160 }
161
bt_mesh_get_adv_duration(void)162 static int32_t bt_mesh_get_adv_duration(void)
163 {
164 uint16_t duration, adv_int;
165 uint8_t xmit;
166
167 xmit = bt_mesh_net_transmit_get(); /* Network transmit */
168 adv_int = BLE_MESH_TRANSMIT_INT(xmit);
169 duration = (BLE_MESH_TRANSMIT_COUNT(xmit) + 1) * (adv_int + 10);
170
171 return (int32_t)duration;
172 }
173
bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx * ctx,struct net_buf_simple * msg,uint32_t opcode,int32_t timeout)174 static int32_t bt_mesh_client_calc_timeout(struct bt_mesh_msg_ctx *ctx,
175 struct net_buf_simple *msg,
176 uint32_t opcode, int32_t timeout)
177 {
178 int32_t seg_retrans_to = 0, duration = 0, time = 0;
179 uint8_t seg_count = 0, seg_retrans_num = 0;
180 bool need_seg = false;
181 uint8_t mic_size = 0;
182
183 if (msg->len > BLE_MESH_SDU_UNSEG_MAX || ctx->send_rel) {
184 need_seg = true; /* Needs segmentation */
185 }
186
187 mic_size = (need_seg && net_buf_simple_tailroom(msg) >= BLE_MESH_MIC_LONG) ?
188 BLE_MESH_MIC_LONG : BLE_MESH_MIC_SHORT;
189
190 if (need_seg) {
191 /* Based on the message length, calculate how many segments are needed.
192 * All the messages sent from here are access messages.
193 */
194 seg_retrans_num = bt_mesh_get_seg_retrans_num();
195 seg_retrans_to = bt_mesh_get_seg_retrans_timeout(ctx->send_ttl);
196 seg_count = (msg->len + mic_size - 1) / 12U + 1U;
197
198 duration = bt_mesh_get_adv_duration();
199
200 /* Currenlty only consider the time consumption of the same segmented
201 * messages, but if there are other messages between any two retrans-
202 * missions of the same segmented messages, then the whole time will
203 * be longer.
204 *
205 * Since the transport behavior has been changed, i.e. start retransmit
206 * timer after the last segment is sent, so we can simplify the timeout
207 * calculation here. And the retransmit timer will be started event if
208 * the attempts reaches ZERO when the dst is a unicast address.
209 */
210 int32_t seg_duration = seg_count * (duration + HCI_TIME_FOR_START_ADV);
211 time = (seg_duration + seg_retrans_to) * seg_retrans_num;
212
213 BT_INFO("Original timeout %dms, calculated timeout %dms", timeout, time);
214
215 if (time < timeout) {
216 /* If the calculated time is smaller than the input timeout value,
217 * then use the original timeout value.
218 */
219 time = timeout;
220 }
221 } else {
222 /* For unsegmented access messages, directly use the timeout
223 * value from the application layer.
224 */
225 time = timeout;
226 }
227
228 BT_INFO("Client message 0x%08x with timeout %dms", opcode, time);
229
230 return time;
231 }
232
msg_send_start(uint16_t duration,int err,void * cb_data)233 static void msg_send_start(uint16_t duration, int err, void *cb_data)
234 {
235 bt_mesh_client_node_t *node = cb_data;
236
237 BT_DBG("%s, duration %ums", __func__, duration);
238
239 if (err) {
240 if (!k_delayed_work_free(&node->timer)) {
241 bt_mesh_client_free_node(node);
242 }
243 return;
244 }
245
246 k_delayed_work_submit(&node->timer, node->timeout);
247 }
248
249 static const struct bt_mesh_send_cb send_cb = {
250 .start = msg_send_start,
251 .end = NULL,
252 };
253
bt_mesh_client_send_msg(bt_mesh_client_common_param_t * param,struct net_buf_simple * msg,bool need_ack,k_work_handler_t timer_handler)254 int bt_mesh_client_send_msg(bt_mesh_client_common_param_t *param,
255 struct net_buf_simple *msg, bool need_ack,
256 k_work_handler_t timer_handler)
257 {
258 bt_mesh_client_internal_data_t *internal = NULL;
259 bt_mesh_client_user_data_t *client = NULL;
260 bt_mesh_client_node_t *node = NULL;
261 int err = 0;
262
263 if (!param || !param->model || !msg) {
264 BT_ERR("%s, Invalid parameter", __func__);
265 return -EINVAL;
266 }
267
268 client = (bt_mesh_client_user_data_t *)param->model->user_data;
269 if (!client) {
270 BT_ERR("Invalid client user data");
271 return -EINVAL;
272 }
273
274 internal = (bt_mesh_client_internal_data_t *)client->internal_data;
275 if (!internal) {
276 BT_ERR("Invalid client internal data");
277 return -EINVAL;
278 }
279
280 if (param->ctx.addr == BLE_MESH_ADDR_UNASSIGNED) {
281 BT_ERR("Invalid DST 0x%04x", param->ctx.addr);
282 return -EINVAL;
283 }
284
285 if (bt_mesh_set_client_model_role(param->model, param->msg_role)) {
286 BT_ERR("Failed to set client role");
287 return -EIO;
288 }
289
290 if (need_ack == false || !BLE_MESH_ADDR_IS_UNICAST(param->ctx.addr)) {
291 /* 1. If this is an unacknowledged message, send it directly.
292 * 2. If this is an acknowledged message, but the destination
293 * is not a unicast address, e.g. a group/virtual address,
294 * then all the corresponding responses will be treated as
295 * publish messages, and no timeout will be used.
296 */
297 err = bt_mesh_model_send(param->model, ¶m->ctx, msg, param->cb, param->cb_data);
298 if (err) {
299 BT_ERR("Failed to send client message 0x%08x", param->opcode);
300 }
301 return err;
302 }
303
304 if (!timer_handler) {
305 BT_ERR("Invalid timeout handler");
306 return -EINVAL;
307 }
308
309 if (bt_mesh_client_check_node_in_list(&internal->queue, param->ctx.addr)) {
310 BT_ERR("Busy sending message to DST 0x%04x", param->ctx.addr);
311 return -EBUSY;
312 }
313
314 /* Don't forget to free the node in the timeout (timer_handler) function. */
315 node = (bt_mesh_client_node_t *)bt_mesh_calloc(sizeof(bt_mesh_client_node_t));
316 if (!node) {
317 BT_ERR("%s, Out of memory", __func__);
318 return -ENOMEM;
319 }
320
321 memcpy(&node->ctx, ¶m->ctx, sizeof(struct bt_mesh_msg_ctx));
322 node->ctx.model = param->model;
323 node->opcode = param->opcode;
324 node->op_pending = bt_mesh_client_get_status_op(client->op_pair, client->op_pair_size, param->opcode);
325 if (node->op_pending == 0U) {
326 BT_ERR("Not found the status opcode in op_pair list");
327 bt_mesh_free(node);
328 return -EINVAL;
329 }
330 node->timeout = bt_mesh_client_calc_timeout(¶m->ctx, msg, param->opcode,
331 param->msg_timeout ? param->msg_timeout : CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT);
332
333 if (k_delayed_work_init(&node->timer, timer_handler)) {
334 BT_ERR("Failed to create a timer");
335 bt_mesh_free(node);
336 return -EIO;
337 }
338
339 bt_mesh_list_lock();
340 sys_slist_append(&internal->queue, &node->client_node);
341 bt_mesh_list_unlock();
342
343 /* "bt_mesh_model_send" will post the mesh packet to the mesh adv queue.
344 * Due to the higher priority of adv_thread (than btc task), we need to
345 * send the packet after the list item "node" is initialized properly.
346 */
347 err = bt_mesh_model_send(param->model, ¶m->ctx, msg, &send_cb, node);
348 if (err) {
349 BT_ERR("Failed to send client message 0x%08x", node->opcode);
350 k_delayed_work_free(&node->timer);
351 bt_mesh_client_free_node(node);
352 }
353
354 return err;
355 }
356
357 static bt_mesh_mutex_t client_model_lock;
358
bt_mesh_client_model_mutex_new(void)359 static inline void bt_mesh_client_model_mutex_new(void)
360 {
361 if (!client_model_lock.mutex) {
362 bt_mesh_mutex_create(&client_model_lock);
363 }
364 }
365
366 #if CONFIG_BLE_MESH_DEINIT
bt_mesh_client_model_mutex_free(void)367 static inline void bt_mesh_client_model_mutex_free(void)
368 {
369 bt_mesh_mutex_free(&client_model_lock);
370 }
371 #endif /* CONFIG_BLE_MESH_DEINIT */
372
bt_mesh_client_model_lock(void)373 void bt_mesh_client_model_lock(void)
374 {
375 bt_mesh_mutex_lock(&client_model_lock);
376 }
377
bt_mesh_client_model_unlock(void)378 void bt_mesh_client_model_unlock(void)
379 {
380 bt_mesh_mutex_unlock(&client_model_lock);
381 }
382
bt_mesh_client_init(struct bt_mesh_model * model)383 int bt_mesh_client_init(struct bt_mesh_model *model)
384 {
385 bt_mesh_client_internal_data_t *data = NULL;
386 bt_mesh_client_user_data_t *client = NULL;
387
388 if (!model || !model->op) {
389 BT_ERR("Invalid vendor client model");
390 return -EINVAL;
391 }
392
393 client = (bt_mesh_client_user_data_t *)model->user_data;
394 if (!client) {
395 BT_ERR("No vendor client context provided");
396 return -EINVAL;
397 }
398
399 if (!client->internal_data) {
400 data = bt_mesh_calloc(sizeof(bt_mesh_client_internal_data_t));
401 if (!data) {
402 BT_ERR("%s, Out of memory", __func__);
403 return -ENOMEM;
404 }
405
406 /* Init the client data queue */
407 sys_slist_init(&data->queue);
408
409 client->model = model;
410 client->internal_data = data;
411 } else {
412 bt_mesh_client_clear_list(client->internal_data);
413 }
414
415 bt_mesh_client_model_mutex_new();
416
417 return 0;
418 }
419
420 #if CONFIG_BLE_MESH_DEINIT
bt_mesh_client_deinit(struct bt_mesh_model * model)421 int bt_mesh_client_deinit(struct bt_mesh_model *model)
422 {
423 bt_mesh_client_user_data_t *client = NULL;
424
425 if (!model) {
426 BT_ERR("Invalid vendor client model");
427 return -EINVAL;
428 }
429
430 client = (bt_mesh_client_user_data_t *)model->user_data;
431 if (!client) {
432 BT_ERR("No vendor client context provided");
433 return -EINVAL;
434 }
435
436 if (client->internal_data) {
437 /* Remove items from the list */
438 bt_mesh_client_clear_list(client->internal_data);
439
440 /* Free the allocated internal data */
441 bt_mesh_free(client->internal_data);
442 client->internal_data = NULL;
443 }
444
445 bt_mesh_client_model_mutex_free();
446
447 return 0;
448 }
449 #endif /* CONFIG_BLE_MESH_DEINIT */
450
bt_mesh_client_free_node(bt_mesh_client_node_t * node)451 int bt_mesh_client_free_node(bt_mesh_client_node_t *node)
452 {
453 bt_mesh_client_internal_data_t *internal = NULL;
454 bt_mesh_client_user_data_t *client = NULL;
455
456 if (!node || !node->ctx.model) {
457 BT_ERR("Invalid client list item");
458 return -EINVAL;
459 }
460
461 client = (bt_mesh_client_user_data_t *)node->ctx.model->user_data;
462 if (!client) {
463 BT_ERR("Invalid client user data");
464 return -EINVAL;
465 }
466
467 internal = (bt_mesh_client_internal_data_t *)client->internal_data;
468 if (!internal) {
469 BT_ERR("Invalid client internal data");
470 return -EINVAL;
471 }
472
473 // Release the client node from the queue
474 bt_mesh_list_lock();
475 sys_slist_find_and_remove(&internal->queue, &node->client_node);
476 bt_mesh_list_unlock();
477 // Free the node
478 bt_mesh_free(node);
479
480 return 0;
481 }
482
bt_mesh_client_clear_list(void * data)483 int bt_mesh_client_clear_list(void *data)
484 {
485 bt_mesh_client_internal_data_t *internal = NULL;
486 bt_mesh_client_node_t *node = NULL;
487
488 if (!data) {
489 BT_ERR("%s, Invalid parameter", __func__);
490 return -EINVAL;
491 }
492
493 internal = (bt_mesh_client_internal_data_t *)data;
494
495 bt_mesh_list_lock();
496 while (!sys_slist_is_empty(&internal->queue)) {
497 node = (void *)sys_slist_get_not_empty(&internal->queue);
498 k_delayed_work_free(&node->timer);
499 bt_mesh_free(node);
500 }
501 bt_mesh_list_unlock();
502
503 return 0;
504 }
505
bt_mesh_set_client_model_role(struct bt_mesh_model * model,uint8_t role)506 int bt_mesh_set_client_model_role(struct bt_mesh_model *model, uint8_t role)
507 {
508 bt_mesh_client_user_data_t *client = NULL;
509
510 if (!model) {
511 BT_ERR("Invalid client model");
512 return -EINVAL;
513 }
514
515 client = (bt_mesh_client_user_data_t *)model->user_data;
516 if (!client) {
517 BT_ERR("Invalid client user data");
518 return -EINVAL;
519 }
520
521 if (role >= ROLE_NVAL) {
522 BT_ERR("Invalid client role 0x%02x", role);
523 return -EINVAL;
524 }
525
526 client->msg_role = role;
527 return 0;
528 }
529