1 /*
2  * Copyright (C) 2018-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <aos/kernel.h>
6 
7 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_DEBUG_GENIE_TRANSPORT)
8 #include "common/log.h"
9 #include "mesh.h"
10 #include "mesh/access.h"
11 #include "net.h"
12 #include "access.h"
13 
14 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
15 #include "adv.h"
16 #endif
17 
18 #include "genie_service.h"
19 
20 static uint16_t last_src_addr = BT_MESH_ADDR_TMALL_GENIE;
21 static genie_transport_tid_queue_t tid_queue[RECV_MSG_TID_QUEUE_SIZE];
22 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
23 static struct k_timer scan_off_timer;
24 #endif
25 
26 /**
27  * send_list was used to save the unconfirmed vendor messages
28  * retransmit_timer was used to control when the vendor messages saved in send_list will be resent
29  * */
30 static sys_dlist_t send_list;
31 static struct k_timer retransmit_timer;
32 static aos_mutex_t transport_mutex;
33 
34 /** @def genie_transport_msg_node_generate
35  *
36  *  @brief duplicate genie_transport_model_param_t and save to genie_transport_node_t
37  *
38  *  @param pointer to the vendor model message to be duplicated
39  *
40  *  @return pointer to genie_transport_node_t for success, NULL for failure
41  */
genie_transport_msg_node_generate(genie_transport_model_param_t * p_model_msg)42 static genie_transport_node_t *genie_transport_msg_node_generate(genie_transport_model_param_t *p_model_msg)
43 {
44     genie_transport_node_t *p_node = NULL;
45 
46     if (p_model_msg->retry > VENDOR_MODEL_MSG_MAX_RETRY_TIMES)
47     {
48         p_model_msg->retry = VENDOR_MODEL_MSG_MAX_RETRY_TIMES;
49     }
50 
51     p_node = hal_malloc(sizeof(genie_transport_node_t) + p_model_msg->len);
52     if (!p_node)
53     {
54         BT_ERR("malloc for genie_transport_node_t failed");
55         return NULL;
56     }
57 
58     memcpy(&p_node->msg, p_model_msg, sizeof(genie_transport_model_param_t));
59     BT_DBG("p_node->msg:%p, data:%p, %p", &p_node->msg, &p_node->msg.data, &p_node->msg.data + 1);
60     p_node->msg.data = (uint8_t *)(&p_node->msg.data + 1);
61     memcpy(p_node->msg.data, p_model_msg->data, p_model_msg->len);
62     BT_DBG("p_model_msg->data:%p, %s", p_model_msg->data, bt_hex(p_model_msg->data, p_model_msg->len));
63     BT_DBG("p_node->msg.data:%p, %s", p_node->msg.data, bt_hex(p_node->msg.data, p_node->msg.len));
64     p_node->timeout = k_uptime_get() + p_model_msg->retry_period;
65 
66     p_node->left_retry = p_model_msg->retry;
67 
68     return p_node;
69 }
70 
genie_transport_find_by_tid(uint8_t tid)71 static genie_transport_model_param_t *genie_transport_find_by_tid(uint8_t tid)
72 {
73     sys_dnode_t *p_node = NULL;
74     genie_transport_model_param_t *p_msg = NULL;
75     genie_transport_node_t *p_msg_node = NULL;
76 
77     SYS_DLIST_FOR_EACH_NODE(&send_list, p_node)
78     {
79         p_msg_node = CONTAINER_OF(p_node, genie_transport_node_t, node);
80         if (p_msg_node == NULL)
81         {
82             continue;
83         }
84 
85         p_msg = &p_msg_node->msg;
86 
87         if (p_msg->tid == tid)
88         {
89             return p_msg;
90         }
91     }
92 
93     return NULL;
94 }
95 
96 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
scan_off_timer_cb(void * p_timer,void * args)97 static void scan_off_timer_cb(void *p_timer, void *args)
98 {
99     bt_mesh_scan_disable();
100 }
101 
send_start_cb(u16_t duration,int err,void * cb_data)102 static void send_start_cb(u16_t duration, int err, void *cb_data)
103 {
104     bt_mesh_scan_disable();
105 }
106 
send_end_cb(int err,void * cb_data)107 static void send_end_cb(int err, void *cb_data)
108 {
109     bt_mesh_scan_enable();
110     k_timer_start(&scan_off_timer, CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND);
111 }
112 #endif
113 
114 /** @def genie_transport_model_send
115  *
116  *  @brief send the vendor model message
117  *
118  *  @param pointer to the message to be sent
119  *
120  *  @return 0 for success; negative for failure
121  */
genie_transport_model_send(genie_transport_model_param_t * p_model_msg)122 static int16_t genie_transport_model_send(genie_transport_model_param_t *p_model_msg)
123 {
124     int16_t err = -1;
125     struct bt_mesh_model_pub *p_pub = &genie_model_pub;
126     struct net_buf_simple *p_msg = p_pub->msg;
127     struct bt_mesh_model *p_model = bt_mesh_model_find_vnd(p_model_msg->p_elem, CONFIG_MESH_VENDOR_COMPANY_ID, CONFIG_MESH_VENDOR_MODEL_SRV);
128     struct bt_mesh_msg_ctx ctx;
129 
130     if (!p_model)
131     {
132         BT_ERR("cannot find vendor model server %p\n", p_model_msg->p_elem);
133         return err;
134     }
135 
136     BT_DBG("p_model:%p, cid:0x%x, id:0x%x, retry:%d", p_model, p_model->vnd.company, p_model->vnd.id, p_model_msg->retry);
137 
138     BT_DBG("tid:%02x opcode:%02x", p_model_msg->tid, p_model_msg->opid);
139     BT_DBG("p_model_msg->data:%p, %d, %s", p_model_msg, p_model_msg->len, bt_hex(p_model_msg->data, p_model_msg->len));
140 
141     //prepare buffer
142     bt_mesh_model_msg_init(p_msg, BT_MESH_MODEL_OP_3(p_model_msg->opid, CONFIG_MESH_VENDOR_COMPANY_ID));
143     net_buf_simple_add_u8(p_msg, p_model_msg->tid);
144     if (p_model_msg->len)
145     {
146         net_buf_simple_add_mem(p_msg, p_model_msg->data, p_model_msg->len);
147     }
148 
149     ctx.app_idx = bt_mesh_model_get_appkey_id(p_model_msg->p_elem, p_model);
150     ctx.net_idx = bt_mesh_model_get_netkey_id(p_model_msg->p_elem);
151     ctx.addr = p_model_msg->dst_addr;
152     ctx.send_ttl = GENIE_TRANSPORT_DEFAULT_TTL;
153     ctx.send_rel = 0;
154 
155     if (ctx.addr == BT_MESH_ADDR_UNASSIGNED)
156     {
157         ctx.addr = BT_MESH_ADDR_TMALL_GENIE;
158     }
159 
160 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
161     static struct bt_mesh_send_cb model_send_cb = {
162         .start = send_start_cb,
163         .end = send_end_cb,
164     };
165 
166     err = bt_mesh_model_send(p_model, &ctx, p_msg, &model_send_cb, NULL);
167 #else
168     err = bt_mesh_model_send(p_model, &ctx, p_msg, NULL, NULL);
169 #endif
170 
171     if (err)
172     {
173         BT_ERR("genie transport send fail:%d\n", err);
174     }
175     else
176     {
177         BT_DBG("genie transport send success");
178     }
179 
180     return err;
181 }
182 
183 /** @def genie_transport_append_mesg
184  *
185  *  @brief duplicate genie_transport_model_param_t and append it to vendor model message list to be monitored
186  *
187  *  @param pointer to the vendor model message to be duplicated
188  *
189  *  @return 0 for success; negative for failure
190  */
genie_transport_append_mesg(genie_transport_model_param_t * p_model_msg)191 static int16_t genie_transport_append_mesg(genie_transport_model_param_t *p_model_msg)
192 {
193     genie_transport_node_t *p_msg_node = NULL;
194 
195     BT_DBG("append msg:%p, opid:%x, retry:%d, head:%p, node:%p", p_model_msg, p_model_msg->opid, p_model_msg->retry, &send_list, &p_msg_node->node);
196     if (sys_dlist_node_number(&send_list) >= CONFIG_VENDOR_SEND_MSG_MAX)
197     {
198         GENIE_LOG_WARN("send list full");
199         return -1;
200     }
201 
202     aos_mutex_lock(&transport_mutex, AOS_WAIT_FOREVER);
203     p_msg_node = genie_transport_msg_node_generate(p_model_msg);
204     if (!p_msg_node)
205     {
206         return -1;
207     }
208 
209     sys_dlist_append(&send_list, &p_msg_node->node);
210     aos_mutex_unlock(&transport_mutex);
211 
212     //Check retry timer, if timer is not started yet, start it
213     if (!k_timer_is_started(&retransmit_timer))
214     {
215         k_timer_start(&retransmit_timer, p_model_msg->retry_period);
216     }
217 
218     return 0;
219 }
220 
genie_transport_check_tid(u16_t src_addr,uint8_t tid,uint8_t elem_id)221 E_MESH_ERROR_TYPE genie_transport_check_tid(u16_t src_addr, uint8_t tid, uint8_t elem_id)
222 {
223     static uint8_t cur_index = 0;
224     uint8_t i = cur_index;
225     uint8_t ri = 0;
226     uint32_t cur_time = k_uptime_get();
227     uint32_t end_time = 0;
228 
229     if (src_addr >= TMALL_GENIE_UADDR_START && src_addr <= TMALL_GENIE_UADDR_END)
230     {
231         src_addr = TMALL_GENIE_UADDR_START;
232     }
233 
234     while (i < cur_index + RECV_MSG_TID_QUEUE_SIZE)
235     {
236         ri = i % RECV_MSG_TID_QUEUE_SIZE;
237         if ((tid_queue[ri].tid == tid) && (tid_queue[ri].addr == src_addr) && (tid_queue[ri].elemid == elem_id))
238         {
239             end_time = tid_queue[ri].time + GENIE_TRANSPORT_DEDUPLICATE_DURATION;
240             if (cur_time < end_time)
241             {
242                 break;
243             }
244         }
245         i++;
246     }
247     if (i < cur_index + RECV_MSG_TID_QUEUE_SIZE)
248     {
249         return MESH_TID_REPEAT;
250     }
251     else
252     {
253         tid_queue[cur_index].tid = tid;
254         tid_queue[cur_index].elemid = elem_id;
255         tid_queue[cur_index].addr = src_addr;
256         tid_queue[cur_index].time = cur_time;
257         cur_index++;
258         cur_index %= RECV_MSG_TID_QUEUE_SIZE;
259 
260         return MESH_SUCCESS;
261     }
262 }
263 
genie_transport_src_addr_set(uint16_t src_addr)264 void genie_transport_src_addr_set(uint16_t src_addr)
265 {
266     last_src_addr = src_addr;
267 }
268 
genie_transport_src_addr_get()269 uint16_t genie_transport_src_addr_get()
270 {
271     return last_src_addr;
272 }
273 
274 /** @def transport_msg_node_free
275  *
276  *  @brief free the vendor model message node struct's memory
277  *
278  *  @param pointer to the vendor model message node to be freed
279  *
280  *  @return 0 for success; negative for failure
281  */
transport_msg_node_free(genie_transport_node_t * p_node)282 static int16_t transport_msg_node_free(genie_transport_node_t *p_node)
283 {
284     hal_free(p_node);
285 
286     return 0;
287 }
288 
transport_remove_by_tid(uint8_t tid)289 static int transport_remove_by_tid(uint8_t tid)
290 {
291     sys_dnode_t *p_node = NULL;
292     sys_dnode_t *p_node_safe = NULL;
293 
294     if (sys_dlist_is_empty(&send_list))
295     {
296         return -1;
297     }
298 
299     aos_mutex_lock(&transport_mutex, AOS_WAIT_FOREVER);
300     SYS_DLIST_FOR_EACH_NODE_SAFE(&send_list, p_node, p_node_safe)
301     {
302         genie_transport_model_param_t *p_msg = NULL;
303         genie_transport_node_t *p_msg_node = NULL;
304 
305         p_msg_node = CONTAINER_OF(p_node, genie_transport_node_t, node);
306         p_msg = &p_msg_node->msg;
307 
308         BT_DBG("msg %02x", p_msg->tid);
309         if (p_msg->tid == tid)
310         {
311             sys_dlist_remove(p_node);
312             transport_msg_node_free((genie_transport_node_t *)p_node);
313             return 0;
314         }
315     }
316     aos_mutex_unlock(&transport_mutex);
317 
318     return -1;
319 }
320 
transport_get_send_timeout(uint16_t payload_len)321 static uint16_t transport_get_send_timeout(uint16_t payload_len)
322 {
323     return GENIE_TRANSPORT_EACH_PDU_TIMEOUT * genie_transport_get_seg_count(payload_len);
324 }
325 
genie_transport_send_model(genie_transport_model_param_t * p_model_msg)326 int genie_transport_send_model(genie_transport_model_param_t *p_model_msg)
327 {
328     int r = -1;
329 
330     if (!p_model_msg || !p_model_msg->data || p_model_msg->len == 0 || !bt_mesh_is_provisioned())
331     {
332         BT_ERR("send param err");
333         return r;
334     }
335 
336     BT_DBG("opcode:0x%x, tid:%d, len:%d", p_model_msg->opid, p_model_msg->tid, p_model_msg->len);
337     BT_DBG("payload:%s", p_model_msg->len ? bt_hex(p_model_msg->data, p_model_msg->len) : "empty");
338 
339     switch (p_model_msg->opid)
340     {
341     case VENDOR_OP_ATTR_STATUS:
342     case VENDOR_OP_ATTR_INDICATE:
343     case VENDOR_OP_ATTR_INDICATE_TG:
344     case VENDOR_OP_ATTR_TRANS_MSG:
345     case VENDOR_OP_ATTR_TRANS_INDICATE:
346     {
347         if (p_model_msg->tid == 0)
348         {
349             p_model_msg->tid = genie_transport_gen_tid();
350         }
351 
352         /**
353      * no need to duplicate the following messages
354      * 1. retry <= 0 - the message won't want to be resent
355      * 2. tid device tid is [0x80, 0xBF]
356      * 3. opcode is not VENDOR_OP_ATTR_INDICATE/VENDOR_OP_ATTR_INDICATE_TG/VENDOR_OP_ATTR_TRANS_INDICATE
357      * 4. already duplicated or CONFIME/CONFIME_TG
358      * */
359         if ((p_model_msg->tid >= GENIE_TRANSPORT_TID_MIN &&
360              p_model_msg->tid <= GENIE_TRANSPORT_TID_MAX))
361         {
362             if (genie_transport_find_by_tid(p_model_msg->tid) != NULL)
363             {
364                 transport_remove_by_tid(p_model_msg->tid); //remove old
365             }
366 
367             if ((p_model_msg->opid != VENDOR_OP_ATTR_STATUS) && (p_model_msg->opid != VENDOR_OP_ATTR_TRANS_MSG))
368             {
369                 //append for retransmit
370                 if (p_model_msg->retry_period > 0)
371                 {
372                     r = genie_transport_append_mesg(p_model_msg); //append new
373                 }
374             }
375 
376             GENIE_LOG_INFO("SendTID(%02X)\n", p_model_msg->tid);
377             r = genie_transport_model_send(p_model_msg); //Send at first time
378         }
379         else
380         {
381             BT_WARN("no send");
382         }
383     }
384     break;
385     default:
386     {
387         BT_WARN("unknown opid:0x%x", p_model_msg->opid);
388     }
389     break;
390     }
391 
392     return r;
393 }
394 
genie_transport_send_payload(genie_transport_payload_param_t * payload_param)395 int genie_transport_send_payload(genie_transport_payload_param_t *payload_param)
396 {
397     genie_transport_model_param_t transport_model_param = {0};
398 
399     if (payload_param == NULL || payload_param->p_payload == NULL)
400     {
401         GENIE_LOG_ERR("invalid param");
402         return -1;
403     }
404 
405     memset(&transport_model_param, 0, sizeof(genie_transport_model_param_t));
406     transport_model_param.opid = payload_param->opid;
407     transport_model_param.tid = payload_param->tid;
408     transport_model_param.data = payload_param->p_payload;
409     transport_model_param.len = payload_param->payload_len;
410     transport_model_param.p_elem = genie_mesh_get_primary_element();
411     transport_model_param.retry_period = transport_get_send_timeout(payload_param->payload_len);
412     transport_model_param.retry = payload_param->retry_cnt;
413     transport_model_param.result_cb = payload_param->result_cb;
414     transport_model_param.dst_addr = payload_param->dst_addr;
415 
416     return genie_transport_send_model(&transport_model_param);
417 }
418 
419 /** @def genie_transport_gen_tid
420  *
421  *  @brief generate tid used in vendor model message
422  *
423  *  @param NULL
424  *
425  *  @return tid with range of [0x80, 0xBF]
426  */
genie_transport_gen_tid(void)427 uint8_t genie_transport_gen_tid(void)
428 {
429     static uint8_t tid = GENIE_TRANSPORT_TID_MAX;
430 
431     if (tid == GENIE_TRANSPORT_TID_MAX) //When bootup use rand tid
432     {
433         bt_rand(&tid, 1);
434         tid &= 0x3F;
435     }
436     else
437     {
438         tid = (tid + 1) & 0x3F;
439     }
440 
441     return (tid | 0x80);
442 }
443 
genie_transport_get_seg_count(uint16_t msg_len)444 uint8_t genie_transport_get_seg_count(uint16_t msg_len)
445 {
446     if (msg_len <= 11) //One byte is Lower PDU header
447     {
448         return 1;
449     }
450 
451     msg_len -= 8; //SZMIC
452 
453     return (msg_len % GENIE_TRANSPORT_EACH_PDU_SIZE) ? (msg_len / GENIE_TRANSPORT_EACH_PDU_SIZE + 2) : (msg_len / GENIE_TRANSPORT_EACH_PDU_SIZE + 1);
454 }
455 
genie_transport_tx_in_progress(void)456 bool genie_transport_tx_in_progress(void)
457 {
458     if (!sys_dlist_is_empty(&send_list))
459     {
460         return true;
461     }
462 
463     return false;
464 }
465 
466 /** @def retransmit_timer_cb
467  *
468  *  @brief timeout handler for the retransmit_timer
469  *
470  *  @param p_timer - pointer to the timer; args - pointer to send_list
471  *
472  *  @return N/A
473  */
retransmit_timer_cb(void * p_timer,void * args)474 static void retransmit_timer_cb(void *p_timer, void *args)
475 {
476     sys_dlist_t *p_head = (sys_dlist_t *)args;
477     sys_dnode_t *p_node = NULL;
478     sys_dnode_t *p_node_safe = NULL;
479     uint32_t nearest = 0;
480     genie_transport_node_t *p_msg_node = NULL;
481     genie_transport_model_param_t *p_msg = NULL;
482 
483     BT_DBG("retransmit_timer timeout, p_head:%p", p_head);
484 
485     /**
486      * 1. go through p_head
487      * 2. resend the no responsed messages if timeout happens and refresh timeout value
488      * */
489     aos_mutex_lock(&transport_mutex, AOS_WAIT_FOREVER);
490     SYS_DLIST_FOR_EACH_NODE_SAFE(p_head, p_node, p_node_safe)
491     {
492         p_msg_node = CONTAINER_OF(p_node, genie_transport_node_t, node);
493         nearest = p_msg_node->msg.retry_period;
494         p_msg = &p_msg_node->msg;
495         BT_DBG("msg:%p, opid:%d, left:%d\n", p_msg, p_msg->opid, p_msg_node->left_retry);
496 
497         if (p_msg_node->timeout <= k_uptime_get())
498         {
499             BT_DBG("timeout - msg:%p, opid:%x, left:%d\n", p_msg, p_msg->opid, p_msg_node->left_retry);
500             if (p_msg_node->left_retry-- == 0)
501             {
502                 GENIE_LOG_INFO("TID(%02X) timeout\n", p_msg_node->msg.tid);
503                 if (p_msg_node->msg.result_cb)
504                 {
505                     p_msg_node->msg.result_cb(SEND_RESULT_TIMEOUT);
506                 }
507                 sys_dlist_remove(p_node);
508                 transport_msg_node_free((genie_transport_node_t *)p_node);
509                 break;
510             }
511             GENIE_LOG_INFO("ReTID(%02X), LR(%d)\n", p_msg->tid, p_msg_node->left_retry);
512             genie_transport_model_send(p_msg);
513             p_msg_node->timeout = k_uptime_get() + p_msg_node->msg.retry_period;
514         }
515         else
516         {
517             if (nearest > p_msg_node->timeout)
518             {
519                 nearest = p_msg_node->timeout;
520             }
521         }
522     }
523     aos_mutex_unlock(&transport_mutex);
524 
525     /* start new timer */
526     if (!sys_dlist_is_empty(p_head))
527     {
528         k_timer_start(&retransmit_timer, nearest);
529         BT_DBG("restart retry timer, timeout:%d\n", nearest);
530     }
531     else
532     {
533         k_timer_stop(&retransmit_timer);
534         BT_DBG("list empty, stop timer\n");
535     }
536 
537     return;
538 }
539 
540 /** @def genie_transport_ack
541  *
542  *  @brief check received vendor message's tid
543  *
544  *  @param pointer to send_list, tid of the received vendor model message
545  *
546  *  @return 0 for success; negative for failure
547  */
genie_transport_ack(uint8_t tid)548 int genie_transport_ack(uint8_t tid)
549 {
550     sys_dnode_t *p_node = NULL;
551     sys_dnode_t *p_node_safe = NULL;
552 
553     if (sys_dlist_is_empty(&send_list))
554     {
555         return 0;
556     }
557 
558     /**
559      * go through message list and dequeue the vendor model's message and free it if received message
560      * s tid equals this message's tid
561      * */
562     BT_DBG("recv %02x\n", tid);
563     aos_mutex_lock(&transport_mutex, AOS_WAIT_FOREVER);
564     SYS_DLIST_FOR_EACH_NODE_SAFE(&send_list, p_node, p_node_safe)
565     {
566         genie_transport_model_param_t *p_msg = NULL;
567         genie_transport_node_t *p_msg_node = NULL;
568 
569         p_msg_node = CONTAINER_OF(p_node, genie_transport_node_t, node);
570         p_msg = &p_msg_node->msg;
571 
572         BT_DBG("msg %02x\n", p_msg->tid);
573         if (p_msg->tid == tid)
574         {
575             BT_DBG("dequeue msg:%p, opid:%x, retry:%d\n", p_msg, p_msg->opid, p_msg->retry);
576             if (p_msg->result_cb)
577             {
578                 p_msg->result_cb(SEND_RESULT_SUCCESS);
579             }
580 
581             sys_dlist_remove(p_node);
582             transport_msg_node_free((genie_transport_node_t *)p_node);
583             break;
584         }
585     }
586     aos_mutex_unlock(&transport_mutex);
587 
588     return 0;
589 }
590 
genie_transport_init(void)591 void genie_transport_init(void)
592 {
593     sys_dlist_init(&send_list);
594     k_timer_init(&retransmit_timer, retransmit_timer_cb, &send_list);
595     aos_mutex_new(&transport_mutex);
596 
597 #ifdef CONFIG_SCAN_DURATION_AFTER_GENIE_MODEL_SEND
598     k_timer_init(&scan_off_timer, scan_off_timer_cb, NULL);
599 #endif
600 }
601