• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*  Bluetooth Mesh */
2 
3 /*
4  * Copyright (c) 2017 Intel Corporation
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  */
8 
9 #include "syscfg/syscfg.h"
10 #define MESH_LOG_MODULE BLE_MESH_LOW_POWER_LOG
11 
12 #if MYNEWT_VAL(BLE_MESH_LOW_POWER)
13 
14 #include <stdint.h>
15 
16 #include "mesh/mesh.h"
17 #include "mesh_priv.h"
18 #include "crypto.h"
19 #include "adv.h"
20 #include "net.h"
21 #include "transport.h"
22 #include "access.h"
23 #include "beacon.h"
24 #include "foundation.h"
25 #include "lpn.h"
26 
27 #if MYNEWT_VAL(BLE_MESH_LPN_AUTO)
28 #define LPN_AUTO_TIMEOUT          K_SECONDS(MYNEWT_VAL(BLE_MESH_LPN_AUTO_TIMEOUT))
29 #else
30 #define LPN_AUTO_TIMEOUT          0
31 #endif
32 
33 #define LPN_RECV_DELAY            MYNEWT_VAL(BLE_MESH_LPN_RECV_DELAY)
34 #define SCAN_LATENCY              min(MYNEWT_VAL(BLE_MESH_LPN_SCAN_LATENCY), \
35                       LPN_RECV_DELAY)
36 
37 #define FRIEND_REQ_RETRY_TIMEOUT  K_SECONDS(MYNEWT_VAL(BLE_MESH_LPN_RETRY_TIMEOUT))
38 
39 #define FRIEND_REQ_WAIT           K_MSEC(100)
40 #define FRIEND_REQ_SCAN           K_SECONDS(1)
41 #define FRIEND_REQ_TIMEOUT        (FRIEND_REQ_WAIT + FRIEND_REQ_SCAN)
42 
43 #define POLL_RETRY_TIMEOUT        K_MSEC(100)
44 
45 #define REQ_RETRY_DURATION(lpn)  (4 * (LPN_RECV_DELAY + (lpn)->adv_duration + \
46                        (lpn)->recv_win + POLL_RETRY_TIMEOUT))
47 
48 #define POLL_TIMEOUT_INIT     (MYNEWT_VAL(BLE_MESH_LPN_INIT_POLL_TIMEOUT) * 100)
49 #define POLL_TIMEOUT_MAX(lpn)   ((MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT) * 100) - \
50                  REQ_RETRY_DURATION(lpn))
51 #define REQ_ATTEMPTS(lpn)     (POLL_TIMEOUT_MAX(lpn) < K_SECONDS(3) ? 2 : 4)
52 
53 #define CLEAR_ATTEMPTS        2
54 
55 #define LPN_CRITERIA ((MYNEWT_VAL(BLE_MESH_LPN_MIN_QUEUE_SIZE)) | \
56               (MYNEWT_VAL(BLE_MESH_LPN_RSSI_FACTOR) << 3) | \
57               (MYNEWT_VAL(BLE_MESH_LPN_RECV_WIN_FACTOR) << 5))
58 
59 #define POLL_TO(to) { (u8_t)((to) >> 16), (u8_t)((to) >> 8), (u8_t)(to) }
60 #define LPN_POLL_TO POLL_TO(MYNEWT_VAL(BLE_MESH_LPN_POLL_TIMEOUT))
61 
62 /* 2 transmissions, 20ms interval */
63 #define POLL_XMIT BT_MESH_TRANSMIT(1, 20)
64 
65 static void (*lpn_cb)(u16_t friend_addr, bool established);
66 
67 #if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
state2str(int state)68 static const char *state2str(int state)
69 {
70     switch (state) {
71         case BT_MESH_LPN_DISABLED:
72             return "disabled";
73 
74         case BT_MESH_LPN_CLEAR:
75             return "clear";
76 
77         case BT_MESH_LPN_TIMER:
78             return "timer";
79 
80         case BT_MESH_LPN_ENABLED:
81             return "enabled";
82 
83         case BT_MESH_LPN_REQ_WAIT:
84             return "req wait";
85 
86         case BT_MESH_LPN_WAIT_OFFER:
87             return "wait offer";
88 
89         case BT_MESH_LPN_ESTABLISHED:
90             return "established";
91 
92         case BT_MESH_LPN_RECV_DELAY:
93             return "recv delay";
94 
95         case BT_MESH_LPN_WAIT_UPDATE:
96             return "wait update";
97 
98         default:
99             return "(unknown)";
100     }
101 }
102 #endif
103 
lpn_set_state(int state)104 static inline void lpn_set_state(int state)
105 {
106 #if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
107     BT_DBG("%s -> %s", state2str(bt_mesh.lpn.state), state2str(state));
108 #endif
109     bt_mesh.lpn.state = state;
110 }
111 
group_zero(atomic_t * target)112 static inline void group_zero(atomic_t *target)
113 {
114 #if CONFIG_BT_MESH_LPN_GROUPS > 32
115     int i;
116 
117     for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) {
118         atomic_set(&target[i], 0);
119     }
120 
121 #else
122     atomic_set(target, 0);
123 #endif
124 }
125 
group_set(atomic_t * target,atomic_t * source)126 static inline void group_set(atomic_t *target, atomic_t *source)
127 {
128 #if CONFIG_BT_MESH_LPN_GROUPS > 32
129     int i;
130 
131     for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) {
132         atomic_or(&target[i], atomic_get(&source[i]));
133     }
134 
135 #else
136     atomic_or(target, atomic_get(source));
137 #endif
138 }
139 
group_clear(atomic_t * target,atomic_t * source)140 static inline void group_clear(atomic_t *target, atomic_t *source)
141 {
142 #if CONFIG_BT_MESH_LPN_GROUPS > 32
143     int i;
144 
145     for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) {
146         atomic_and(&target[i], ~atomic_get(&source[i]));
147     }
148 
149 #else
150     atomic_and(target, ~atomic_get(source));
151 #endif
152 }
153 
154 static void clear_friendship(bool force, bool disable);
155 
friend_clear_sent(int err,void * user_data)156 static void friend_clear_sent(int err, void *user_data)
157 {
158     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
159     /* We're switching away from Low Power behavior, so permanently
160      * enable scanning.
161      */
162     bt_mesh_scan_enable();
163     lpn->req_attempts++;
164 
165     if (err) {
166         BT_ERR("Sending Friend Request failed (err %d)", err);
167         lpn_set_state(BT_MESH_LPN_ENABLED);
168         clear_friendship(false, lpn->disable);
169         return;
170     }
171 
172     lpn_set_state(BT_MESH_LPN_CLEAR);
173     k_delayed_work_submit(&lpn->timer, FRIEND_REQ_TIMEOUT);
174 }
175 
176 static const struct bt_mesh_send_cb clear_sent_cb = {
177     .end = friend_clear_sent,
178 };
179 
send_friend_clear(void)180 static int send_friend_clear(void)
181 {
182     struct bt_mesh_msg_ctx ctx = {
183         .net_idx     = bt_mesh.sub[0].net_idx,
184         .app_idx     = BT_MESH_KEY_UNUSED,
185         .addr        = bt_mesh.lpn.frnd,
186         .send_ttl    = 0,
187     };
188     struct bt_mesh_net_tx tx = {
189         .sub = &bt_mesh.sub[0],
190         .ctx = &ctx,
191         .src = bt_mesh_primary_addr(),
192         .xmit = bt_mesh_net_transmit_get(),
193     };
194     struct bt_mesh_ctl_friend_clear req = {
195         .lpn_addr    = sys_cpu_to_be16(tx.src),
196         .lpn_counter = sys_cpu_to_be16(bt_mesh.lpn.counter),
197     };
198     BT_DBG("");
199     return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_CLEAR, &req,
200                             sizeof(req), NULL, &clear_sent_cb, NULL);
201 }
202 
clear_friendship(bool force,bool disable)203 static void clear_friendship(bool force, bool disable)
204 {
205     struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get();
206     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
207     BT_DBG("force %u disable %u", force, disable);
208 
209     if (!force && lpn->established && !lpn->clear_success &&
210             lpn->req_attempts < CLEAR_ATTEMPTS) {
211         send_friend_clear();
212         lpn->disable = disable;
213         return;
214     }
215 
216     bt_mesh_rx_reset();
217     k_delayed_work_cancel(&lpn->timer);
218     friend_cred_del(bt_mesh.sub[0].net_idx, lpn->frnd);
219 
220     if (lpn->clear_success) {
221         lpn->old_friend = BT_MESH_ADDR_UNASSIGNED;
222     } else {
223         lpn->old_friend = lpn->frnd;
224     }
225 
226     if (lpn_cb && lpn->frnd != BT_MESH_ADDR_UNASSIGNED) {
227         lpn_cb(lpn->frnd, false);
228     }
229 
230     lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
231     lpn->fsn = 0;
232     lpn->req_attempts = 0;
233     lpn->recv_win = 0;
234     lpn->queue_size = 0;
235     lpn->disable = 0;
236     lpn->sent_req = 0;
237     lpn->established = 0;
238     lpn->clear_success = 0;
239     group_zero(lpn->added);
240     group_zero(lpn->pending);
241     group_zero(lpn->to_remove);
242     /* Set this to 1 to force group subscription when the next
243      * Friendship is created, in case lpn->groups doesn't get
244      * modified meanwhile.
245      */
246     lpn->groups_changed = 1;
247 
248     if (cfg->hb_pub.feat & BT_MESH_FEAT_LOW_POWER) {
249         bt_mesh_heartbeat_send();
250     }
251 
252     if (disable) {
253         lpn_set_state(BT_MESH_LPN_DISABLED);
254         return;
255     }
256 
257     lpn_set_state(BT_MESH_LPN_ENABLED);
258     k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT);
259 }
260 
friend_req_sent(u16_t duration,int err,void * user_data)261 static void friend_req_sent(u16_t duration, int err, void *user_data)
262 {
263     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
264 
265     if (err) {
266         BT_ERR("Sending Friend Request failed (err %d)", err);
267         return;
268     }
269 
270     lpn->adv_duration = duration;
271 
272     if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
273         k_delayed_work_submit(&lpn->timer, FRIEND_REQ_WAIT);
274         lpn_set_state(BT_MESH_LPN_REQ_WAIT);
275     } else {
276         k_delayed_work_submit(&lpn->timer,
277                               duration + FRIEND_REQ_TIMEOUT);
278         lpn_set_state(BT_MESH_LPN_WAIT_OFFER);
279     }
280 }
281 
282 static const struct bt_mesh_send_cb friend_req_sent_cb = {
283     .start = friend_req_sent,
284 };
285 
send_friend_req(struct bt_mesh_lpn * lpn)286 static int send_friend_req(struct bt_mesh_lpn *lpn)
287 {
288     const struct bt_mesh_comp *comp = bt_mesh_comp_get();
289     struct bt_mesh_msg_ctx ctx = {
290         .net_idx  = bt_mesh.sub[0].net_idx,
291         .app_idx  = BT_MESH_KEY_UNUSED,
292         .addr     = BT_MESH_ADDR_FRIENDS,
293         .send_ttl = 0,
294     };
295     struct bt_mesh_net_tx tx = {
296         .sub = &bt_mesh.sub[0],
297         .ctx = &ctx,
298         .src = bt_mesh_primary_addr(),
299         .xmit = POLL_XMIT,
300     };
301     struct bt_mesh_ctl_friend_req req = {
302         .criteria    = LPN_CRITERIA,
303         .recv_delay  = LPN_RECV_DELAY,
304         .poll_to     = LPN_POLL_TO,
305         .prev_addr   = lpn->old_friend,
306         .num_elem    = comp->elem_count,
307         .lpn_counter = sys_cpu_to_be16(lpn->counter),
308     };
309     BT_DBG("");
310     return bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_REQ, &req,
311                             sizeof(req), NULL, &friend_req_sent_cb, NULL);
312 }
313 
req_sent(u16_t duration,int err,void * user_data)314 static void req_sent(u16_t duration, int err, void *user_data)
315 {
316     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
317 #if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
318     BT_DBG("req 0x%02x duration %u err %d state %s",
319            lpn->sent_req, duration, err, state2str(lpn->state));
320 #endif
321 
322     if (err) {
323         BT_ERR("Sending request failed (err %d)", err);
324         lpn->sent_req = 0;
325         group_zero(lpn->pending);
326         return;
327     }
328 
329     lpn->req_attempts++;
330     lpn->adv_duration = duration;
331 
332     if (lpn->established || IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
333         lpn_set_state(BT_MESH_LPN_RECV_DELAY);
334         /* We start scanning a bit early to elimitate risk of missing
335          * response data due to HCI and other latencies.
336          */
337         k_delayed_work_submit(&lpn->timer,
338                               LPN_RECV_DELAY - SCAN_LATENCY);
339     } else {
340         k_delayed_work_submit(&lpn->timer,
341                               LPN_RECV_DELAY + duration +
342                               lpn->recv_win);
343     }
344 }
345 
346 static const struct bt_mesh_send_cb req_sent_cb = {
347     .start = req_sent,
348 };
349 
send_friend_poll(void)350 static int send_friend_poll(void)
351 {
352     struct bt_mesh_msg_ctx ctx = {
353         .net_idx     = bt_mesh.sub[0].net_idx,
354         .app_idx     = BT_MESH_KEY_UNUSED,
355         .addr        = bt_mesh.lpn.frnd,
356         .send_ttl    = 0,
357     };
358     struct bt_mesh_net_tx tx = {
359         .sub = &bt_mesh.sub[0],
360         .ctx = &ctx,
361         .src = bt_mesh_primary_addr(),
362         .xmit = POLL_XMIT,
363         .friend_cred = true,
364     };
365     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
366     u8_t fsn = lpn->fsn;
367     int err;
368     BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req);
369 
370     if (lpn->sent_req) {
371         if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) {
372             lpn->pending_poll = 1;
373         }
374 
375         return 0;
376     }
377 
378     err = bt_mesh_ctl_send(&tx, TRANS_CTL_OP_FRIEND_POLL, &fsn, 1,
379                            NULL, &req_sent_cb, NULL);
380     if (err == 0) {
381         lpn->pending_poll = 0;
382         lpn->sent_req = TRANS_CTL_OP_FRIEND_POLL;
383     }
384 
385     return err;
386 }
387 
bt_mesh_lpn_disable(bool force)388 void bt_mesh_lpn_disable(bool force)
389 {
390     if (bt_mesh.lpn.state == BT_MESH_LPN_DISABLED) {
391         return;
392     }
393 
394     clear_friendship(force, true);
395 }
396 
bt_mesh_lpn_set(bool enable)397 int bt_mesh_lpn_set(bool enable)
398 {
399     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
400 
401     if (enable) {
402         if (lpn->state != BT_MESH_LPN_DISABLED) {
403             return 0;
404         }
405     } else {
406         if (lpn->state == BT_MESH_LPN_DISABLED) {
407             return 0;
408         }
409     }
410 
411     if (!bt_mesh_is_provisioned()) {
412         if (enable) {
413             lpn_set_state(BT_MESH_LPN_ENABLED);
414         } else {
415             lpn_set_state(BT_MESH_LPN_DISABLED);
416         }
417 
418         return 0;
419     }
420 
421     if (enable) {
422         lpn_set_state(BT_MESH_LPN_ENABLED);
423 
424         if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
425             bt_mesh_scan_disable();
426         }
427 
428         send_friend_req(lpn);
429     } else {
430         if (IS_ENABLED(CONFIG_BT_MESH_LPN_AUTO) &&
431                 lpn->state == BT_MESH_LPN_TIMER) {
432             k_delayed_work_cancel(&lpn->timer);
433             lpn_set_state(BT_MESH_LPN_DISABLED);
434         } else {
435             bt_mesh_lpn_disable(false);
436         }
437     }
438 
439     return 0;
440 }
441 
friend_response_received(struct bt_mesh_lpn * lpn)442 static void friend_response_received(struct bt_mesh_lpn *lpn)
443 {
444     BT_DBG("lpn->sent_req 0x%02x", lpn->sent_req);
445 
446     if (lpn->sent_req == TRANS_CTL_OP_FRIEND_POLL) {
447         lpn->fsn++;
448     }
449 
450     k_delayed_work_cancel(&lpn->timer);
451     bt_mesh_scan_disable();
452     lpn_set_state(BT_MESH_LPN_ESTABLISHED);
453     lpn->req_attempts = 0;
454     lpn->sent_req = 0;
455 }
456 
bt_mesh_lpn_msg_received(struct bt_mesh_net_rx * rx)457 void bt_mesh_lpn_msg_received(struct bt_mesh_net_rx *rx)
458 {
459     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
460 
461     if (lpn->state == BT_MESH_LPN_TIMER) {
462         BT_DBG("Restarting establishment timer");
463         k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT);
464         return;
465     }
466 
467     if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) {
468         BT_WARN("Unexpected message withouth a preceding Poll");
469         return;
470     }
471 
472     friend_response_received(lpn);
473     BT_DBG("Requesting more messages from Friend");
474     send_friend_poll();
475 }
476 
bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx * rx,struct os_mbuf * buf)477 int bt_mesh_lpn_friend_offer(struct bt_mesh_net_rx *rx,
478                              struct os_mbuf *buf)
479 {
480     struct bt_mesh_ctl_friend_offer *msg = (void *)buf->om_data;
481     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
482     struct bt_mesh_subnet *sub = rx->sub;
483     struct friend_cred *cred;
484     u16_t frnd_counter;
485     int err;
486 
487     if (buf->om_len < sizeof(*msg)) {
488         BT_WARN("Too short Friend Offer");
489         return -EINVAL;
490     }
491 
492     if (lpn->state != BT_MESH_LPN_WAIT_OFFER) {
493         BT_WARN("Ignoring unexpected Friend Offer");
494         return 0;
495     }
496 
497     if (!msg->recv_win) {
498         BT_WARN("Prohibited ReceiveWindow value");
499         return -EINVAL;
500     }
501 
502     frnd_counter = sys_be16_to_cpu(msg->frnd_counter);
503     BT_DBG("recv_win %u queue_size %u sub_list_size %u rssi %d counter %u",
504            msg->recv_win, msg->queue_size, msg->sub_list_size, msg->rssi,
505            frnd_counter);
506     lpn->frnd = rx->ctx.addr;
507     cred = friend_cred_create(sub, lpn->frnd, lpn->counter, frnd_counter);
508     if (!cred) {
509         lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
510         return -ENOMEM;
511     }
512     k_delayed_work_cancel(&lpn->timer);
513     lpn->recv_win = msg->recv_win;
514     lpn->queue_size = msg->queue_size;
515     err = send_friend_poll();
516     if (err) {
517         friend_cred_clear(cred);
518         lpn->frnd = BT_MESH_ADDR_UNASSIGNED;
519         lpn->recv_win = 0;
520         lpn->queue_size = 0;
521         return err;
522     }
523 
524     lpn->counter++;
525     return 0;
526 }
527 
bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx * rx,struct os_mbuf * buf)528 int bt_mesh_lpn_friend_clear_cfm(struct bt_mesh_net_rx *rx,
529                                  struct os_mbuf *buf)
530 {
531     struct bt_mesh_ctl_friend_clear_confirm *msg = (void *)buf->om_data;
532     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
533     u16_t addr, counter;
534 
535     if (buf->om_len < sizeof(*msg)) {
536         BT_WARN("Too short Friend Clear Confirm");
537         return -EINVAL;
538     }
539 
540     if (lpn->state != BT_MESH_LPN_CLEAR) {
541         BT_WARN("Ignoring unexpected Friend Clear Confirm");
542         return 0;
543     }
544 
545     addr = sys_be16_to_cpu(msg->lpn_addr);
546     counter = sys_be16_to_cpu(msg->lpn_counter);
547     BT_DBG("LPNAddress 0x%04x LPNCounter 0x%04x", addr, counter);
548 
549     if (addr != bt_mesh_primary_addr() || counter != lpn->counter) {
550         BT_WARN("Invalid parameters in Friend Clear Confirm");
551         return 0;
552     }
553 
554     lpn->clear_success = 1;
555     clear_friendship(false, lpn->disable);
556     return 0;
557 }
558 
lpn_group_add(u16_t group)559 static void lpn_group_add(u16_t group)
560 {
561     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
562     u16_t *free_slot = NULL;
563     int i;
564 
565     for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) {
566         if (lpn->groups[i] == group) {
567             atomic_clear_bit(lpn->to_remove, i);
568             return;
569         }
570 
571         if (!free_slot && lpn->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
572             free_slot = &lpn->groups[i];
573         }
574     }
575 
576     if (!free_slot) {
577         BT_WARN("Friend Subscription List exceeded!");
578         return;
579     }
580 
581     *free_slot = group;
582     lpn->groups_changed = 1;
583 }
584 
lpn_group_del(u16_t group)585 static void lpn_group_del(u16_t group)
586 {
587     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
588     int i;
589 
590     for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) {
591         if (lpn->groups[i] == group) {
592             if (atomic_test_bit(lpn->added, i) ||
593                     atomic_test_bit(lpn->pending, i)) {
594                 atomic_set_bit(lpn->to_remove, i);
595                 lpn->groups_changed = 1;
596             } else {
597                 lpn->groups[i] = BT_MESH_ADDR_UNASSIGNED;
598             }
599         }
600     }
601 }
602 
group_popcount(atomic_t * target)603 static inline int group_popcount(atomic_t *target)
604 {
605 #if CONFIG_BT_MESH_LPN_GROUPS > 32
606     int i, count = 0;
607 
608     for (i = 0; i < ARRAY_SIZE(bt_mesh.lpn.added); i++) {
609         count += popcount(atomic_get(&target[i]));
610     }
611 
612 #else
613     return popcount(atomic_get(target));
614 #endif
615 }
616 
sub_update(u8_t op)617 static bool sub_update(u8_t op)
618 {
619     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
620     int added_count = group_popcount(lpn->added);
621     struct bt_mesh_msg_ctx ctx = {
622         .net_idx     = bt_mesh.sub[0].net_idx,
623         .app_idx     = BT_MESH_KEY_UNUSED,
624         .addr        = lpn->frnd,
625         .send_ttl    = 0,
626     };
627     struct bt_mesh_net_tx tx = {
628         .sub = &bt_mesh.sub[0],
629         .ctx = &ctx,
630         .src = bt_mesh_primary_addr(),
631         .xmit = POLL_XMIT,
632         .friend_cred = true,
633     };
634     struct bt_mesh_ctl_friend_sub req;
635     size_t i, g;
636     BT_DBG("op 0x%02x sent_req 0x%02x", op, lpn->sent_req);
637 
638     if (lpn->sent_req) {
639         return false;
640     }
641 
642     for (i = 0, g = 0; i < ARRAY_SIZE(lpn->groups); i++) {
643         if (lpn->groups[i] == BT_MESH_ADDR_UNASSIGNED) {
644             continue;
645         }
646 
647         if (op == TRANS_CTL_OP_FRIEND_SUB_ADD) {
648             if (atomic_test_bit(lpn->added, i)) {
649                 continue;
650             }
651         } else {
652             if (!atomic_test_bit(lpn->to_remove, i)) {
653                 continue;
654             }
655         }
656 
657         if (added_count + g >= lpn->queue_size) {
658             BT_WARN("Friend Queue Size exceeded");
659             break;
660         }
661 
662         req.addr_list[g++] = sys_cpu_to_be16(lpn->groups[i]);
663         atomic_set_bit(lpn->pending, i);
664 
665         if (g == ARRAY_SIZE(req.addr_list)) {
666             break;
667         }
668     }
669 
670     if (g == 0) {
671         group_zero(lpn->pending);
672         return false;
673     }
674 
675     req.xact = lpn->xact_next++;
676 
677     if (bt_mesh_ctl_send(&tx, op, &req, 1 + g * 2, NULL, // 2:byte alignment
678         &req_sent_cb, NULL) < 0) {
679         group_zero(lpn->pending);
680         return false;
681     }
682 
683     lpn->xact_pending = req.xact;
684     lpn->sent_req = op;
685     return true;
686 }
687 
update_timeout(struct bt_mesh_lpn * lpn)688 static void update_timeout(struct bt_mesh_lpn *lpn)
689 {
690     if (lpn->established) {
691         BT_WARN("No response from Friend during ReceiveWindow");
692         bt_mesh_scan_disable();
693         lpn_set_state(BT_MESH_LPN_ESTABLISHED);
694         k_delayed_work_submit(&lpn->timer, POLL_RETRY_TIMEOUT);
695     } else {
696         if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
697             bt_mesh_scan_disable();
698         }
699 
700         if (lpn->req_attempts < 6) { // 6:Analyzing conditions
701             BT_WARN("Retrying first Friend Poll");
702             lpn->sent_req = 0;
703 
704             if (send_friend_poll() == 0) {
705                 return;
706             }
707         }
708 
709         BT_ERR("Timed out waiting for first Friend Update");
710         clear_friendship(false, false);
711     }
712 }
713 
lpn_timeout(struct ble_npl_event * work)714 static void lpn_timeout(struct ble_npl_event *work)
715 {
716     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
717 #if MYNEWT_VAL(BLE_MESH_LOW_POWER_LOG_LVL) == LOG_LEVEL_DEBUG
718     BT_DBG("state: %s", state2str(lpn->state));
719 #endif
720 
721     switch (lpn->state) {
722         case BT_MESH_LPN_DISABLED:
723             break;
724 
725         case BT_MESH_LPN_CLEAR:
726             clear_friendship(false, bt_mesh.lpn.disable);
727             break;
728 
729         case BT_MESH_LPN_TIMER:
730             BT_DBG("Starting to look for Friend nodes");
731             lpn_set_state(BT_MESH_LPN_ENABLED);
732 
733             if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
734                 bt_mesh_scan_disable();
735             }
736 
737         /* fall through */
738         case BT_MESH_LPN_ENABLED:
739             send_friend_req(lpn);
740             break;
741 
742         case BT_MESH_LPN_REQ_WAIT:
743             bt_mesh_scan_enable();
744             k_delayed_work_submit(&lpn->timer,
745                                   lpn->adv_duration + FRIEND_REQ_SCAN);
746             lpn_set_state(BT_MESH_LPN_WAIT_OFFER);
747             break;
748 
749         case BT_MESH_LPN_WAIT_OFFER:
750             BT_WARN("No acceptable Friend Offers received");
751 
752             if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
753                 bt_mesh_scan_disable();
754             }
755 
756             lpn->counter++;
757             lpn_set_state(BT_MESH_LPN_ENABLED);
758             lpn->sent_req = 0U;
759             k_delayed_work_submit(&lpn->timer, FRIEND_REQ_RETRY_TIMEOUT);
760             break;
761 
762         case BT_MESH_LPN_ESTABLISHED:
763             if (lpn->req_attempts < REQ_ATTEMPTS(lpn)) {
764                 u8_t req = lpn->sent_req;
765                 lpn->sent_req = 0;
766 
767                 if (!req || req == TRANS_CTL_OP_FRIEND_POLL) {
768                     send_friend_poll();
769                 } else {
770                     sub_update(req);
771                 }
772 
773                 break;
774             }
775 
776             BT_ERR("No response from Friend after %u retries",
777                    lpn->req_attempts);
778             lpn->req_attempts = 0;
779             clear_friendship(false, false);
780             break;
781 
782         case BT_MESH_LPN_RECV_DELAY:
783             k_delayed_work_submit(&lpn->timer,
784                                   lpn->adv_duration + SCAN_LATENCY +
785                                   lpn->recv_win);
786             bt_mesh_scan_enable();
787             lpn_set_state(BT_MESH_LPN_WAIT_UPDATE);
788             break;
789 
790         case BT_MESH_LPN_WAIT_UPDATE:
791             update_timeout(lpn);
792             break;
793 
794         default:
795             __ASSERT(0, "Unhandled LPN state");
796             break;
797     }
798 }
799 
bt_mesh_lpn_group_add(u16_t group)800 void bt_mesh_lpn_group_add(u16_t group)
801 {
802     BT_DBG("group 0x%04x", group);
803     lpn_group_add(group);
804 
805     if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) {
806         return;
807     }
808 
809     sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
810 }
811 
bt_mesh_lpn_group_del(u16_t * groups,size_t group_count)812 void bt_mesh_lpn_group_del(u16_t *groups, size_t group_count)
813 {
814     int i;
815 
816     for (i = 0; i < group_count; i++) {
817         if (groups[i] != BT_MESH_ADDR_UNASSIGNED) {
818             BT_DBG("group 0x%04x", groups[i]);
819             lpn_group_del(groups[i]);
820         }
821     }
822 
823     if (!bt_mesh_lpn_established() || bt_mesh.lpn.sent_req) {
824         return;
825     }
826 
827     sub_update(TRANS_CTL_OP_FRIEND_SUB_REM);
828 }
829 
poll_timeout(struct bt_mesh_lpn * lpn)830 static s32_t poll_timeout(struct bt_mesh_lpn *lpn)
831 {
832     /* If we're waiting for segment acks keep polling at high freq */
833     if (bt_mesh_tx_in_progress()) {
834         return min(POLL_TIMEOUT_MAX(lpn), K_SECONDS(1));
835     }
836 
837     if (lpn->poll_timeout < POLL_TIMEOUT_MAX(lpn)) {
838         lpn->poll_timeout *= 2; // 2:byte alignment
839         lpn->poll_timeout = min(lpn->poll_timeout,
840                                 POLL_TIMEOUT_MAX(lpn));
841     }
842 
843     BT_DBG("Poll Timeout is %ums", (unsigned) lpn->poll_timeout);
844     return lpn->poll_timeout;
845 }
846 
bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx * rx,struct os_mbuf * buf)847 int bt_mesh_lpn_friend_sub_cfm(struct bt_mesh_net_rx *rx,
848                                struct os_mbuf *buf)
849 {
850     struct bt_mesh_ctl_friend_sub_confirm *msg = (void *)buf->om_data;
851     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
852 
853     if (buf->om_len < sizeof(*msg)) {
854         BT_WARN("Too short Friend Subscription Confirm");
855         return -EINVAL;
856     }
857 
858     BT_DBG("xact 0x%02x", msg->xact);
859 
860     if (!lpn->sent_req) {
861         BT_WARN("No pending subscription list message");
862         return 0;
863     }
864 
865     if (msg->xact != lpn->xact_pending) {
866         BT_WARN("Transaction mismatch (0x%02x != 0x%02x)",
867                 msg->xact, lpn->xact_pending);
868         return 0;
869     }
870 
871     if (lpn->sent_req == TRANS_CTL_OP_FRIEND_SUB_ADD) {
872         group_set(lpn->added, lpn->pending);
873         group_zero(lpn->pending);
874     } else if (lpn->sent_req == TRANS_CTL_OP_FRIEND_SUB_REM) {
875         int i;
876         group_clear(lpn->added, lpn->pending);
877 
878         for (i = 0; i < ARRAY_SIZE(lpn->groups); i++) {
879             if (atomic_test_and_clear_bit(lpn->pending, i) &&
880                     atomic_test_and_clear_bit(lpn->to_remove, i)) {
881                 lpn->groups[i] = BT_MESH_ADDR_UNASSIGNED;
882             }
883         }
884     } else {
885         BT_WARN("Unexpected Friend Subscription Confirm");
886         return 0;
887     }
888 
889     friend_response_received(lpn);
890 
891     if (lpn->groups_changed) {
892         sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
893         sub_update(TRANS_CTL_OP_FRIEND_SUB_REM);
894 
895         if (!lpn->sent_req) {
896             lpn->groups_changed = 0;
897         }
898     }
899 
900     if (lpn->pending_poll) {
901         send_friend_poll();
902     }
903 
904     if (!lpn->sent_req) {
905         k_delayed_work_submit(&lpn->timer, poll_timeout(lpn));
906     }
907 
908     return 0;
909 }
910 
bt_mesh_lpn_friend_update(struct bt_mesh_net_rx * rx,struct os_mbuf * buf)911 int bt_mesh_lpn_friend_update(struct bt_mesh_net_rx *rx,
912                               struct os_mbuf *buf)
913 {
914     struct bt_mesh_ctl_friend_update *msg = (void *)buf->om_data;
915     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
916     struct bt_mesh_subnet *sub = rx->sub;
917     u32_t iv_index;
918 
919     if (buf->om_len < sizeof(*msg)) {
920         BT_WARN("Too short Friend Update");
921         return -EINVAL;
922     }
923 
924     if (lpn->sent_req != TRANS_CTL_OP_FRIEND_POLL) {
925         BT_WARN("Unexpected friend update");
926         return 0;
927     }
928 
929     if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !rx->new_key) {
930         BT_WARN("Ignoring Phase 2 KR Update secured using old key");
931         return 0;
932     }
933 
934     if (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) &&
935             (atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS) ==
936              BT_MESH_IV_UPDATE(msg->flags))) {
937         bt_mesh_beacon_ivu_initiator(false);
938     }
939 
940     if (!lpn->established) {
941         struct bt_mesh_cfg_srv *cfg = bt_mesh_cfg_get();
942 
943         /* This is normally checked on the transport layer, however
944          * in this state we're also still accepting master
945          * credentials so we need to ensure the right ones (Friend
946          * Credentials) were used for this message.
947          */
948         if (!rx->friend_cred) {
949             BT_WARN("Friend Update with wrong credentials");
950             return -EINVAL;
951         }
952 
953         lpn->established = 1;
954         BT_INFO("Friendship established with 0x%04x", lpn->frnd);
955 
956         if (cfg->hb_pub.feat & BT_MESH_FEAT_LOW_POWER) {
957             bt_mesh_heartbeat_send();
958         }
959 
960         if (lpn_cb) {
961             lpn_cb(lpn->frnd, true);
962         }
963 
964         /* Set initial poll timeout */
965         lpn->poll_timeout = min(POLL_TIMEOUT_MAX(lpn),
966                                 POLL_TIMEOUT_INIT);
967     }
968 
969     friend_response_received(lpn);
970     iv_index = sys_be32_to_cpu(msg->iv_index);
971     BT_DBG("flags 0x%02x iv_index 0x%08x md %u", msg->flags,
972            (unsigned) iv_index, msg->md);
973 
974     if (bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(msg->flags),
975         rx->new_key)) {
976         bt_mesh_net_beacon_update(sub);
977     }
978 
979     bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(msg->flags));
980 
981     if (lpn->groups_changed) {
982         sub_update(TRANS_CTL_OP_FRIEND_SUB_ADD);
983         sub_update(TRANS_CTL_OP_FRIEND_SUB_REM);
984 
985         if (!lpn->sent_req) {
986             lpn->groups_changed = 0;
987         }
988     }
989 
990     if (msg->md) {
991         BT_DBG("Requesting for more messages");
992         send_friend_poll();
993     }
994 
995     if (!lpn->sent_req) {
996         k_delayed_work_submit(&lpn->timer, poll_timeout(lpn));
997     }
998 
999     return 0;
1000 }
1001 
bt_mesh_lpn_poll(void)1002 int bt_mesh_lpn_poll(void)
1003 {
1004     if (!bt_mesh.lpn.established) {
1005         return -EAGAIN;
1006     }
1007 
1008     BT_DBG("Requesting more messages");
1009     return send_friend_poll();
1010 }
1011 
bt_mesh_lpn_set_cb(void (* cb)(u16_t friend_addr,bool established))1012 void bt_mesh_lpn_set_cb(void (*cb)(u16_t friend_addr, bool established))
1013 {
1014     lpn_cb = cb;
1015 }
1016 
bt_mesh_lpn_init(void)1017 int bt_mesh_lpn_init(void)
1018 {
1019     struct bt_mesh_lpn *lpn = &bt_mesh.lpn;
1020     BT_DBG("");
1021     k_delayed_work_init(&lpn->timer, lpn_timeout);
1022 
1023     if (lpn->state == BT_MESH_LPN_ENABLED) {
1024         if (IS_ENABLED(CONFIG_BT_MESH_LPN_ESTABLISHMENT)) {
1025             bt_mesh_scan_disable();
1026         } else {
1027             bt_mesh_scan_enable();
1028         }
1029 
1030         send_friend_req(lpn);
1031     } else {
1032         bt_mesh_scan_enable();
1033 
1034         if (IS_ENABLED(CONFIG_BT_MESH_LPN_AUTO)) {
1035             BT_DBG("Waiting %u ms for messages", LPN_AUTO_TIMEOUT);
1036             lpn_set_state(BT_MESH_LPN_TIMER);
1037             k_delayed_work_submit(&lpn->timer, LPN_AUTO_TIMEOUT);
1038         }
1039     }
1040 
1041     return 0;
1042 }
1043 
1044 #endif /* MYNEWT_VAL(BLE_MESH_LOW_POWER) */
1045