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