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