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