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, &param->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, &param->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(&param->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, &param->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