xref: /nrf52832-nimble/packages/NimBLE-latest/nimble/host/mesh/src/beacon.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
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 <errno.h>
10*042d53a7SEvalZero #include <assert.h>
11*042d53a7SEvalZero #include "os/os_mbuf.h"
12*042d53a7SEvalZero #include "mesh/mesh.h"
13*042d53a7SEvalZero 
14*042d53a7SEvalZero #include "syscfg/syscfg.h"
15*042d53a7SEvalZero #define BT_DBG_ENABLED (MYNEWT_VAL(BLE_MESH_DEBUG_BEACON))
16*042d53a7SEvalZero #include "host/ble_hs_log.h"
17*042d53a7SEvalZero 
18*042d53a7SEvalZero #include "adv.h"
19*042d53a7SEvalZero #include "mesh_priv.h"
20*042d53a7SEvalZero #include "net.h"
21*042d53a7SEvalZero #include "prov.h"
22*042d53a7SEvalZero #include "crypto.h"
23*042d53a7SEvalZero #include "beacon.h"
24*042d53a7SEvalZero #include "foundation.h"
25*042d53a7SEvalZero 
26*042d53a7SEvalZero #define UNPROVISIONED_INTERVAL    (K_SECONDS(5))
27*042d53a7SEvalZero #define PROVISIONED_INTERVAL      (K_SECONDS(10))
28*042d53a7SEvalZero 
29*042d53a7SEvalZero #define BEACON_TYPE_UNPROVISIONED  0x00
30*042d53a7SEvalZero #define BEACON_TYPE_SECURE         0x01
31*042d53a7SEvalZero 
32*042d53a7SEvalZero /* 3 transmissions, 20ms interval */
33*042d53a7SEvalZero #define UNPROV_XMIT                BT_MESH_TRANSMIT(2, 20)
34*042d53a7SEvalZero 
35*042d53a7SEvalZero /* 1 transmission, 20ms interval */
36*042d53a7SEvalZero #define PROV_XMIT                  BT_MESH_TRANSMIT(0, 20)
37*042d53a7SEvalZero 
38*042d53a7SEvalZero static struct k_delayed_work beacon_timer;
39*042d53a7SEvalZero 
cache_check(u8_t data[21])40*042d53a7SEvalZero static struct bt_mesh_subnet *cache_check(u8_t data[21])
41*042d53a7SEvalZero {
42*042d53a7SEvalZero 	int i;
43*042d53a7SEvalZero 
44*042d53a7SEvalZero 	for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
45*042d53a7SEvalZero 		struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
46*042d53a7SEvalZero 
47*042d53a7SEvalZero 		if (sub->net_idx == BT_MESH_KEY_UNUSED) {
48*042d53a7SEvalZero 			continue;
49*042d53a7SEvalZero 		}
50*042d53a7SEvalZero 
51*042d53a7SEvalZero 		if (!memcmp(sub->beacon_cache, data, 21)) {
52*042d53a7SEvalZero 			return sub;
53*042d53a7SEvalZero 		}
54*042d53a7SEvalZero 	}
55*042d53a7SEvalZero 
56*042d53a7SEvalZero 	return NULL;
57*042d53a7SEvalZero }
58*042d53a7SEvalZero 
cache_add(u8_t data[21],struct bt_mesh_subnet * sub)59*042d53a7SEvalZero static void cache_add(u8_t data[21], struct bt_mesh_subnet *sub)
60*042d53a7SEvalZero {
61*042d53a7SEvalZero 	memcpy(sub->beacon_cache, data, 21);
62*042d53a7SEvalZero }
63*042d53a7SEvalZero 
beacon_complete(int err,void * user_data)64*042d53a7SEvalZero static void beacon_complete(int err, void *user_data)
65*042d53a7SEvalZero {
66*042d53a7SEvalZero 	struct bt_mesh_subnet *sub = user_data;
67*042d53a7SEvalZero 
68*042d53a7SEvalZero 	BT_DBG("err %d", err);
69*042d53a7SEvalZero 
70*042d53a7SEvalZero 	sub->beacon_sent = k_uptime_get_32();
71*042d53a7SEvalZero }
72*042d53a7SEvalZero 
bt_mesh_beacon_create(struct bt_mesh_subnet * sub,struct os_mbuf * buf)73*042d53a7SEvalZero void bt_mesh_beacon_create(struct bt_mesh_subnet *sub,
74*042d53a7SEvalZero 			   struct os_mbuf *buf)
75*042d53a7SEvalZero {
76*042d53a7SEvalZero 	u8_t flags = bt_mesh_net_flags(sub);
77*042d53a7SEvalZero 	struct bt_mesh_subnet_keys *keys;
78*042d53a7SEvalZero 
79*042d53a7SEvalZero 	net_buf_simple_add_u8(buf, BEACON_TYPE_SECURE);
80*042d53a7SEvalZero 
81*042d53a7SEvalZero 	if (sub->kr_flag) {
82*042d53a7SEvalZero 		keys = &sub->keys[1];
83*042d53a7SEvalZero 	} else {
84*042d53a7SEvalZero 		keys = &sub->keys[0];
85*042d53a7SEvalZero 	}
86*042d53a7SEvalZero 
87*042d53a7SEvalZero 	net_buf_simple_add_u8(buf, flags);
88*042d53a7SEvalZero 
89*042d53a7SEvalZero 	/* Network ID */
90*042d53a7SEvalZero 	net_buf_simple_add_mem(buf, keys->net_id, 8);
91*042d53a7SEvalZero 
92*042d53a7SEvalZero 	/* IV Index */
93*042d53a7SEvalZero 	net_buf_simple_add_be32(buf, bt_mesh.iv_index);
94*042d53a7SEvalZero 
95*042d53a7SEvalZero 	net_buf_simple_add_mem(buf, sub->auth, 8);
96*042d53a7SEvalZero 
97*042d53a7SEvalZero 	BT_DBG("net_idx 0x%04x flags 0x%02x NetID %s", sub->net_idx,
98*042d53a7SEvalZero 	       flags, bt_hex(keys->net_id, 8));
99*042d53a7SEvalZero 	BT_DBG("IV Index 0x%08x Auth %s", bt_mesh.iv_index,
100*042d53a7SEvalZero 	       bt_hex(sub->auth, 8));
101*042d53a7SEvalZero }
102*042d53a7SEvalZero 
103*042d53a7SEvalZero /* If the interval has passed or is within 5 seconds from now send a beacon */
104*042d53a7SEvalZero #define BEACON_THRESHOLD(sub) (K_SECONDS(10 * ((sub)->beacons_last + 1)) - \
105*042d53a7SEvalZero 			       K_SECONDS(5))
106*042d53a7SEvalZero 
secure_beacon_send(void)107*042d53a7SEvalZero static int secure_beacon_send(void)
108*042d53a7SEvalZero {
109*042d53a7SEvalZero 	static const struct bt_mesh_send_cb send_cb = {
110*042d53a7SEvalZero 		.end = beacon_complete,
111*042d53a7SEvalZero 	};
112*042d53a7SEvalZero 	u32_t now = k_uptime_get_32();
113*042d53a7SEvalZero 	int i;
114*042d53a7SEvalZero 
115*042d53a7SEvalZero 	BT_DBG("");
116*042d53a7SEvalZero 
117*042d53a7SEvalZero 	for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
118*042d53a7SEvalZero 		struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
119*042d53a7SEvalZero 		struct os_mbuf *buf;
120*042d53a7SEvalZero 		u32_t time_diff;
121*042d53a7SEvalZero 
122*042d53a7SEvalZero 		if (sub->net_idx == BT_MESH_KEY_UNUSED) {
123*042d53a7SEvalZero 			continue;
124*042d53a7SEvalZero 		}
125*042d53a7SEvalZero 
126*042d53a7SEvalZero 		time_diff = now - sub->beacon_sent;
127*042d53a7SEvalZero 		if (time_diff < K_SECONDS(600) &&
128*042d53a7SEvalZero 		    time_diff < BEACON_THRESHOLD(sub)) {
129*042d53a7SEvalZero 			continue;
130*042d53a7SEvalZero 		}
131*042d53a7SEvalZero 
132*042d53a7SEvalZero 		buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, PROV_XMIT,
133*042d53a7SEvalZero 					 K_NO_WAIT);
134*042d53a7SEvalZero 		if (!buf) {
135*042d53a7SEvalZero 			BT_ERR("Unable to allocate beacon buffer");
136*042d53a7SEvalZero 			return -ENOBUFS;
137*042d53a7SEvalZero 		}
138*042d53a7SEvalZero 
139*042d53a7SEvalZero 		bt_mesh_beacon_create(sub, buf);
140*042d53a7SEvalZero 
141*042d53a7SEvalZero 		bt_mesh_adv_send(buf, &send_cb, sub);
142*042d53a7SEvalZero 		net_buf_unref(buf);
143*042d53a7SEvalZero 	}
144*042d53a7SEvalZero 
145*042d53a7SEvalZero 	return 0;
146*042d53a7SEvalZero }
147*042d53a7SEvalZero 
unprovisioned_beacon_send(void)148*042d53a7SEvalZero static int unprovisioned_beacon_send(void)
149*042d53a7SEvalZero {
150*042d53a7SEvalZero #if (MYNEWT_VAL(BLE_MESH_PB_ADV))
151*042d53a7SEvalZero 	const struct bt_mesh_prov *prov;
152*042d53a7SEvalZero 	u8_t uri_hash[16] = { 0 };
153*042d53a7SEvalZero 	struct os_mbuf *buf;
154*042d53a7SEvalZero 	u16_t oob_info;
155*042d53a7SEvalZero 
156*042d53a7SEvalZero 	BT_DBG("unprovisioned_beacon_send");
157*042d53a7SEvalZero 
158*042d53a7SEvalZero 	buf = bt_mesh_adv_create(BT_MESH_ADV_BEACON, UNPROV_XMIT, K_NO_WAIT);
159*042d53a7SEvalZero 	if (!buf) {
160*042d53a7SEvalZero 		BT_ERR("Unable to allocate beacon buffer");
161*042d53a7SEvalZero 		return -ENOBUFS;
162*042d53a7SEvalZero 	}
163*042d53a7SEvalZero 
164*042d53a7SEvalZero 	prov = bt_mesh_prov_get();
165*042d53a7SEvalZero 
166*042d53a7SEvalZero 	net_buf_add_u8(buf, BEACON_TYPE_UNPROVISIONED);
167*042d53a7SEvalZero 	net_buf_add_mem(buf, prov->uuid, 16);
168*042d53a7SEvalZero 
169*042d53a7SEvalZero 	if (prov->uri && bt_mesh_s1(prov->uri, uri_hash) == 0) {
170*042d53a7SEvalZero 		oob_info = prov->oob_info | BT_MESH_PROV_OOB_URI;
171*042d53a7SEvalZero 	} else {
172*042d53a7SEvalZero 		oob_info = prov->oob_info;
173*042d53a7SEvalZero 	}
174*042d53a7SEvalZero 
175*042d53a7SEvalZero 	net_buf_add_be16(buf, oob_info);
176*042d53a7SEvalZero 	net_buf_add_mem(buf, uri_hash, 4);
177*042d53a7SEvalZero 
178*042d53a7SEvalZero 	bt_mesh_adv_send(buf, NULL, NULL);
179*042d53a7SEvalZero 	net_buf_unref(buf);
180*042d53a7SEvalZero 
181*042d53a7SEvalZero 	if (prov->uri) {
182*042d53a7SEvalZero 		size_t len;
183*042d53a7SEvalZero 
184*042d53a7SEvalZero 		buf = bt_mesh_adv_create(BT_MESH_ADV_URI, UNPROV_XMIT,
185*042d53a7SEvalZero 					 K_NO_WAIT);
186*042d53a7SEvalZero 		if (!buf) {
187*042d53a7SEvalZero 			BT_ERR("Unable to allocate URI buffer");
188*042d53a7SEvalZero 			return -ENOBUFS;
189*042d53a7SEvalZero 		}
190*042d53a7SEvalZero 
191*042d53a7SEvalZero 		len = strlen(prov->uri);
192*042d53a7SEvalZero 		if (net_buf_tailroom(buf) < len) {
193*042d53a7SEvalZero 			BT_WARN("Too long URI to fit advertising data");
194*042d53a7SEvalZero 		} else {
195*042d53a7SEvalZero 			net_buf_add_mem(buf, prov->uri, len);
196*042d53a7SEvalZero 			bt_mesh_adv_send(buf, NULL, NULL);
197*042d53a7SEvalZero 		}
198*042d53a7SEvalZero 
199*042d53a7SEvalZero 		net_buf_unref(buf);
200*042d53a7SEvalZero 	}
201*042d53a7SEvalZero 
202*042d53a7SEvalZero #endif /* MYNEWT_VAL(BLE_MESH_PB_ADV) */
203*042d53a7SEvalZero 	return 0;
204*042d53a7SEvalZero }
205*042d53a7SEvalZero 
update_beacon_observation(void)206*042d53a7SEvalZero static void update_beacon_observation(void)
207*042d53a7SEvalZero {
208*042d53a7SEvalZero 	static bool first_half;
209*042d53a7SEvalZero 	int i;
210*042d53a7SEvalZero 
211*042d53a7SEvalZero 	/* Observation period is 20 seconds, whereas the beacon timer
212*042d53a7SEvalZero 	 * runs every 10 seconds. We process what's happened during the
213*042d53a7SEvalZero 	 * window only after the seconnd half.
214*042d53a7SEvalZero 	 */
215*042d53a7SEvalZero 	first_half = !first_half;
216*042d53a7SEvalZero 	if (first_half) {
217*042d53a7SEvalZero 		return;
218*042d53a7SEvalZero 	}
219*042d53a7SEvalZero 
220*042d53a7SEvalZero 	for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
221*042d53a7SEvalZero 		struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
222*042d53a7SEvalZero 
223*042d53a7SEvalZero 		if (sub->net_idx == BT_MESH_KEY_UNUSED) {
224*042d53a7SEvalZero 			continue;
225*042d53a7SEvalZero 		}
226*042d53a7SEvalZero 
227*042d53a7SEvalZero 		sub->beacons_last = sub->beacons_cur;
228*042d53a7SEvalZero 		sub->beacons_cur = 0;
229*042d53a7SEvalZero 	}
230*042d53a7SEvalZero }
231*042d53a7SEvalZero 
beacon_send(struct ble_npl_event * work)232*042d53a7SEvalZero static void beacon_send(struct ble_npl_event *work)
233*042d53a7SEvalZero {
234*042d53a7SEvalZero 	/* Don't send anything if we have an active provisioning link */
235*042d53a7SEvalZero 	if ((MYNEWT_VAL(BLE_MESH_PROV)) && bt_prov_active()) {
236*042d53a7SEvalZero 		k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL);
237*042d53a7SEvalZero 		return;
238*042d53a7SEvalZero 	}
239*042d53a7SEvalZero 
240*042d53a7SEvalZero 	BT_DBG("");
241*042d53a7SEvalZero 
242*042d53a7SEvalZero 	if (bt_mesh_is_provisioned()) {
243*042d53a7SEvalZero 		update_beacon_observation();
244*042d53a7SEvalZero 		secure_beacon_send();
245*042d53a7SEvalZero 
246*042d53a7SEvalZero 		/* Only resubmit if beaconing is still enabled */
247*042d53a7SEvalZero 		if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED ||
248*042d53a7SEvalZero 		    bt_mesh.ivu_initiator) {
249*042d53a7SEvalZero 			k_delayed_work_submit(&beacon_timer,
250*042d53a7SEvalZero 					      PROVISIONED_INTERVAL);
251*042d53a7SEvalZero 		}
252*042d53a7SEvalZero 	} else {
253*042d53a7SEvalZero 		unprovisioned_beacon_send();
254*042d53a7SEvalZero 		k_delayed_work_submit(&beacon_timer, UNPROVISIONED_INTERVAL);
255*042d53a7SEvalZero 	}
256*042d53a7SEvalZero 
257*042d53a7SEvalZero }
258*042d53a7SEvalZero 
secure_beacon_recv(struct os_mbuf * buf)259*042d53a7SEvalZero static void secure_beacon_recv(struct os_mbuf *buf)
260*042d53a7SEvalZero {
261*042d53a7SEvalZero 	u8_t *data, *net_id, *auth;
262*042d53a7SEvalZero 	struct bt_mesh_subnet *sub;
263*042d53a7SEvalZero 	u32_t iv_index;
264*042d53a7SEvalZero 	bool new_key, kr_change, iv_change;
265*042d53a7SEvalZero 	u8_t flags;
266*042d53a7SEvalZero 
267*042d53a7SEvalZero 	if (buf->om_len < 21) {
268*042d53a7SEvalZero 		BT_ERR("Too short secure beacon (len %u)", buf->om_len);
269*042d53a7SEvalZero 		return;
270*042d53a7SEvalZero 	}
271*042d53a7SEvalZero 
272*042d53a7SEvalZero 	sub = cache_check(buf->om_data);
273*042d53a7SEvalZero 	if (sub) {
274*042d53a7SEvalZero 		/* We've seen this beacon before - just update the stats */
275*042d53a7SEvalZero 		goto update_stats;
276*042d53a7SEvalZero 	}
277*042d53a7SEvalZero 
278*042d53a7SEvalZero 	/* So we can add to the cache if auth matches */
279*042d53a7SEvalZero 	data = buf->om_data;
280*042d53a7SEvalZero 
281*042d53a7SEvalZero 	flags = net_buf_simple_pull_u8(buf);
282*042d53a7SEvalZero 	net_id = buf->om_data;
283*042d53a7SEvalZero 	net_buf_simple_pull(buf, 8);
284*042d53a7SEvalZero 	iv_index = net_buf_simple_pull_be32(buf);
285*042d53a7SEvalZero 	auth = buf->om_data;
286*042d53a7SEvalZero 
287*042d53a7SEvalZero 	BT_DBG("flags 0x%02x id %s iv_index 0x%08x",
288*042d53a7SEvalZero 	       flags, bt_hex(net_id, 8), iv_index);
289*042d53a7SEvalZero 
290*042d53a7SEvalZero 	sub = bt_mesh_subnet_find(net_id, flags, iv_index, auth, &new_key);
291*042d53a7SEvalZero 	if (!sub) {
292*042d53a7SEvalZero 		BT_DBG("No subnet that matched beacon");
293*042d53a7SEvalZero 		return;
294*042d53a7SEvalZero 	}
295*042d53a7SEvalZero 
296*042d53a7SEvalZero 	if (sub->kr_phase == BT_MESH_KR_PHASE_2 && !new_key) {
297*042d53a7SEvalZero 		BT_WARN("Ignoring Phase 2 KR Update secured using old key");
298*042d53a7SEvalZero 		return;
299*042d53a7SEvalZero 	}
300*042d53a7SEvalZero 
301*042d53a7SEvalZero 	cache_add(data, sub);
302*042d53a7SEvalZero 
303*042d53a7SEvalZero 	/* If we have NetKey0 accept initiation only from it */
304*042d53a7SEvalZero 	if (bt_mesh_subnet_get(BT_MESH_KEY_PRIMARY) &&
305*042d53a7SEvalZero 	    sub->net_idx != BT_MESH_KEY_PRIMARY) {
306*042d53a7SEvalZero 		BT_WARN("Ignoring secure beacon on non-primary subnet");
307*042d53a7SEvalZero 		goto update_stats;
308*042d53a7SEvalZero 	}
309*042d53a7SEvalZero 
310*042d53a7SEvalZero 	BT_DBG("net_idx 0x%04x iv_index 0x%08x, current iv_index 0x%08x",
311*042d53a7SEvalZero 	       sub->net_idx, iv_index, bt_mesh.iv_index);
312*042d53a7SEvalZero 
313*042d53a7SEvalZero 	if (bt_mesh.ivu_initiator &&
314*042d53a7SEvalZero 	    bt_mesh.iv_update == BT_MESH_IV_UPDATE(flags)) {
315*042d53a7SEvalZero 		bt_mesh_beacon_ivu_initiator(false);
316*042d53a7SEvalZero 	}
317*042d53a7SEvalZero 
318*042d53a7SEvalZero 	iv_change = bt_mesh_net_iv_update(iv_index, BT_MESH_IV_UPDATE(flags));
319*042d53a7SEvalZero 
320*042d53a7SEvalZero 	kr_change = bt_mesh_kr_update(sub, BT_MESH_KEY_REFRESH(flags), new_key);
321*042d53a7SEvalZero 	if (kr_change) {
322*042d53a7SEvalZero 		bt_mesh_net_beacon_update(sub);
323*042d53a7SEvalZero 	}
324*042d53a7SEvalZero 
325*042d53a7SEvalZero 	if (iv_change) {
326*042d53a7SEvalZero 		/* Update all subnets */
327*042d53a7SEvalZero 		bt_mesh_net_sec_update(NULL);
328*042d53a7SEvalZero 	} else if (kr_change) {
329*042d53a7SEvalZero 		/* Key Refresh without IV Update only impacts one subnet */
330*042d53a7SEvalZero 		bt_mesh_net_sec_update(sub);
331*042d53a7SEvalZero 	}
332*042d53a7SEvalZero 
333*042d53a7SEvalZero update_stats:
334*042d53a7SEvalZero 	if (bt_mesh_beacon_get() == BT_MESH_BEACON_ENABLED &&
335*042d53a7SEvalZero 	    sub->beacons_cur < 0xff) {
336*042d53a7SEvalZero 		sub->beacons_cur++;
337*042d53a7SEvalZero 	}
338*042d53a7SEvalZero }
339*042d53a7SEvalZero 
bt_mesh_beacon_recv(struct os_mbuf * buf)340*042d53a7SEvalZero void bt_mesh_beacon_recv(struct os_mbuf *buf)
341*042d53a7SEvalZero {
342*042d53a7SEvalZero 	u8_t type;
343*042d53a7SEvalZero 
344*042d53a7SEvalZero 	BT_DBG("%u bytes: %s", buf->om_len, bt_hex(buf->om_data, buf->om_len));
345*042d53a7SEvalZero 
346*042d53a7SEvalZero 	if (buf->om_len < 1) {
347*042d53a7SEvalZero 		BT_ERR("Too short beacon");
348*042d53a7SEvalZero 		return;
349*042d53a7SEvalZero 	}
350*042d53a7SEvalZero 
351*042d53a7SEvalZero 	type = net_buf_simple_pull_u8(buf);
352*042d53a7SEvalZero 	switch (type) {
353*042d53a7SEvalZero 	case BEACON_TYPE_UNPROVISIONED:
354*042d53a7SEvalZero 		BT_DBG("Ignoring unprovisioned device beacon");
355*042d53a7SEvalZero 		break;
356*042d53a7SEvalZero 	case BEACON_TYPE_SECURE:
357*042d53a7SEvalZero 		secure_beacon_recv(buf);
358*042d53a7SEvalZero 		break;
359*042d53a7SEvalZero 	default:
360*042d53a7SEvalZero 		BT_WARN("Unknown beacon type 0x%02x", type);
361*042d53a7SEvalZero 		break;
362*042d53a7SEvalZero 	}
363*042d53a7SEvalZero }
364*042d53a7SEvalZero 
bt_mesh_beacon_init(void)365*042d53a7SEvalZero void bt_mesh_beacon_init(void)
366*042d53a7SEvalZero {
367*042d53a7SEvalZero 	k_delayed_work_init(&beacon_timer, beacon_send);
368*042d53a7SEvalZero }
369*042d53a7SEvalZero 
bt_mesh_beacon_ivu_initiator(bool enable)370*042d53a7SEvalZero void bt_mesh_beacon_ivu_initiator(bool enable)
371*042d53a7SEvalZero {
372*042d53a7SEvalZero 	bt_mesh.ivu_initiator = enable;
373*042d53a7SEvalZero 
374*042d53a7SEvalZero 	if (enable) {
375*042d53a7SEvalZero 		k_work_submit(&beacon_timer.work);
376*042d53a7SEvalZero 	} else if (bt_mesh_beacon_get() == BT_MESH_BEACON_DISABLED) {
377*042d53a7SEvalZero 		k_delayed_work_cancel(&beacon_timer);
378*042d53a7SEvalZero 	}
379*042d53a7SEvalZero }
380*042d53a7SEvalZero 
bt_mesh_beacon_enable(void)381*042d53a7SEvalZero void bt_mesh_beacon_enable(void)
382*042d53a7SEvalZero {
383*042d53a7SEvalZero 	int i;
384*042d53a7SEvalZero 
385*042d53a7SEvalZero 	if (!bt_mesh_is_provisioned()) {
386*042d53a7SEvalZero 		k_work_submit(&beacon_timer.work);
387*042d53a7SEvalZero 		return;
388*042d53a7SEvalZero 	}
389*042d53a7SEvalZero 
390*042d53a7SEvalZero 	for (i = 0; i < ARRAY_SIZE(bt_mesh.sub); i++) {
391*042d53a7SEvalZero 		struct bt_mesh_subnet *sub = &bt_mesh.sub[i];
392*042d53a7SEvalZero 
393*042d53a7SEvalZero 		if (sub->net_idx == BT_MESH_KEY_UNUSED) {
394*042d53a7SEvalZero 			continue;
395*042d53a7SEvalZero 		}
396*042d53a7SEvalZero 
397*042d53a7SEvalZero 		sub->beacons_last = 0;
398*042d53a7SEvalZero 		sub->beacons_cur = 0;
399*042d53a7SEvalZero 
400*042d53a7SEvalZero 		bt_mesh_net_beacon_update(sub);
401*042d53a7SEvalZero 	}
402*042d53a7SEvalZero 
403*042d53a7SEvalZero 	k_work_submit(&beacon_timer.work);
404*042d53a7SEvalZero }
405*042d53a7SEvalZero 
bt_mesh_beacon_disable(void)406*042d53a7SEvalZero void bt_mesh_beacon_disable(void)
407*042d53a7SEvalZero {
408*042d53a7SEvalZero 	if (!bt_mesh.ivu_initiator) {
409*042d53a7SEvalZero 		k_delayed_work_cancel(&beacon_timer);
410*042d53a7SEvalZero 	}
411*042d53a7SEvalZero }
412