diff --git a/subsys/bluetooth/mesh/beacon.c b/subsys/bluetooth/mesh/beacon.c index a32caa19433..9c47132b7ff 100644 --- a/subsys/bluetooth/mesh/beacon.c +++ b/subsys/bluetooth/mesh/beacon.c @@ -56,38 +56,72 @@ static struct { uint64_t timestamp; } priv_random; +struct beacon_params { + bool private; + union { + const uint8_t *net_id; + struct { + const uint8_t *data; + const uint8_t *random; + }; + }; + const uint8_t *auth; + uint32_t iv_index; + uint8_t flags; + + bool new_key; +}; + #if defined(CONFIG_BT_MESH_PRIV_BEACONS) static int private_beacon_create(struct bt_mesh_subnet *sub, struct net_buf_simple *buf); static int private_beacon_update(struct bt_mesh_subnet *sub); #endif -static bool beacon_cache_match(struct bt_mesh_subnet *sub, void *auth) +static struct bt_mesh_beacon *subnet_beacon_get_by_type(struct bt_mesh_subnet *sub, bool priv) { - return !memcmp(sub->beacon_cache, auth, sizeof(sub->beacon_cache)); +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + return priv ? &sub->priv_beacon : &sub->secure_beacon; +#else + return &sub->secure_beacon; +#endif } -static void cache_add(const uint8_t auth[8], struct bt_mesh_subnet *sub) +static bool beacon_cache_match(struct bt_mesh_subnet *sub, void *data) { - memcpy(sub->beacon_cache, auth, sizeof(sub->beacon_cache)); + struct beacon_params *params; + struct bt_mesh_beacon *beacon; + + params = data; + beacon = subnet_beacon_get_by_type(sub, params->private); + + return !memcmp(beacon->cache, params->auth, sizeof(beacon->cache)); +} + +static void cache_add(const uint8_t auth[8], struct bt_mesh_beacon *beacon) +{ + memcpy(beacon->cache, auth, sizeof(beacon->cache)); } void bt_mesh_beacon_cache_clear(struct bt_mesh_subnet *sub) { - (void)memset(sub->beacon_cache, 0, sizeof(sub->beacon_cache)); + (void)memset(sub->secure_beacon.cache, 0, sizeof(sub->secure_beacon.cache)); +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + (void)memset(sub->priv_beacon.cache, 0, sizeof(sub->priv_beacon.cache)); +#endif } static void beacon_complete(int err, void *user_data) { - struct bt_mesh_subnet *sub = user_data; + struct bt_mesh_beacon *beacon = user_data; LOG_DBG("err %d", err); - sub->beacon_sent = k_uptime_get_32(); + beacon->sent = k_uptime_get_32(); } -static void secure_beacon_create(struct bt_mesh_subnet *sub, - struct net_buf_simple *buf) +static int secure_beacon_create(struct bt_mesh_subnet *sub, + struct net_buf_simple *buf) { uint8_t flags = bt_mesh_net_flags(sub); struct bt_mesh_subnet_keys *keys; @@ -104,11 +138,13 @@ static void secure_beacon_create(struct bt_mesh_subnet *sub, /* IV Index */ net_buf_simple_add_be32(buf, bt_mesh.iv_index); - net_buf_simple_add_mem(buf, sub->auth, 8); + net_buf_simple_add_mem(buf, sub->secure_beacon.auth, 8); LOG_DBG("net_idx 0x%04x flags 0x%02x NetID %s", sub->net_idx, flags, bt_hex(keys->net_id, 8)); - LOG_DBG("IV Index 0x%08x Auth %s", bt_mesh.iv_index, bt_hex(sub->auth, 8)); + LOG_DBG("IV Index 0x%08x Auth %s", bt_mesh.iv_index, bt_hex(sub->secure_beacon.auth, 8)); + + return 0; } #if defined(CONFIG_BT_MESH_PRIV_BEACONS) @@ -148,13 +184,13 @@ static int private_beacon_update(struct bt_mesh_subnet *sub) int err; err = bt_mesh_beacon_encrypt(keys->priv_beacon, flags, bt_mesh.iv_index, - priv_random.val, sub->priv_beacon.data, - sub->auth); + priv_random.val, sub->priv_beacon_ctx.data, + sub->priv_beacon.auth); if (err) { return err; } - sub->priv_beacon.idx = priv_random.idx; + sub->priv_beacon_ctx.idx = priv_random.idx; return 0; } @@ -169,7 +205,7 @@ static int private_beacon_create(struct bt_mesh_subnet *sub, return err; } - if (sub->priv_beacon.idx != priv_random.idx) { + if (sub->priv_beacon_ctx.idx != priv_random.idx) { err = private_beacon_update(sub); if (err) { return err; @@ -178,8 +214,8 @@ static int private_beacon_create(struct bt_mesh_subnet *sub, net_buf_simple_add_u8(buf, BEACON_TYPE_PRIVATE); net_buf_simple_add_mem(buf, priv_random.val, 13); - net_buf_simple_add_mem(buf, sub->priv_beacon.data, 5); - net_buf_simple_add_mem(buf, sub->auth, 8); + net_buf_simple_add_mem(buf, sub->priv_beacon_ctx.data, 5); + net_buf_simple_add_mem(buf, sub->priv_beacon.auth, 8); LOG_DBG("0x%03x", sub->net_idx); return 0; @@ -200,10 +236,18 @@ int bt_mesh_beacon_create(struct bt_mesh_subnet *sub, } /* If the interval has passed or is within 5 seconds from now send a beacon */ -#define BEACON_THRESHOLD(sub) \ - ((10 * ((sub)->beacons_last + 1)) * MSEC_PER_SEC - (5 * MSEC_PER_SEC)) +#define BEACON_THRESHOLD(beacon) \ + ((10 * ((beacon)->last + 1)) * MSEC_PER_SEC - (5 * MSEC_PER_SEC)) -static bool net_beacon_send(struct bt_mesh_subnet *sub, void *cb_data) +static bool secure_beacon_is_running(void) +{ + return bt_mesh_beacon_enabled() || + atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR); +} + +static bool net_beacon_send(struct bt_mesh_subnet *sub, struct bt_mesh_beacon *beacon, + void *cb_data, int (*beacon_create)(struct bt_mesh_subnet *sub, + struct net_buf_simple *buf)) { static const struct bt_mesh_send_cb send_cb = { .end = beacon_complete, @@ -216,10 +260,10 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, void *cb_data) LOG_DBG(""); - time_diff = now - sub->beacon_sent; - time_since_last_recv = now - sub->beacon_recv; + time_diff = now - beacon->sent; + time_since_last_recv = now - beacon->recv; if (time_diff < (600 * MSEC_PER_SEC) && - (time_diff < BEACON_THRESHOLD(sub) || + (time_diff < BEACON_THRESHOLD(beacon) || time_since_last_recv < (10 * MSEC_PER_SEC))) { return false; } @@ -231,15 +275,52 @@ static bool net_beacon_send(struct bt_mesh_subnet *sub, void *cb_data) return true; /* Bail out */ } - err = bt_mesh_beacon_create(sub, &buf->b); - if (err) { - return true; /* Bail out */ + err = beacon_create(sub, &buf->b); + if (!err) { + bt_mesh_adv_send(buf, &send_cb, beacon); } - bt_mesh_adv_send(buf, &send_cb, sub); net_buf_unref(buf); - return false; + return err != 0; +} + +static bool net_beacon_for_subnet_send(struct bt_mesh_subnet *sub, void *cb_data) +{ + bool res = true; + + struct { + struct bt_mesh_beacon *beacon; + bool enabled; + int (*create_fn)(struct bt_mesh_subnet *sub, struct net_buf_simple *buf); + } beacons[] = { + [0] = { + .beacon = &sub->secure_beacon, + .enabled = secure_beacon_is_running(), + .create_fn = secure_beacon_create, + }, +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + [1] = { + .beacon = &sub->priv_beacon, + .enabled = bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED, + .create_fn = private_beacon_create, + }, +#endif + }; + + for (int i = 0; i < ARRAY_SIZE(beacons); i++) { + if (!beacons[i].enabled) { + continue; + } + + res = net_beacon_send(sub, beacons[i].beacon, cb_data, beacons[i].create_fn); + if (res) { + /* Bail out */ + break; + } + } + + return res; } static int unprovisioned_beacon_send(void) @@ -335,8 +416,13 @@ static void unprovisioned_beacon_recv(struct net_buf_simple *buf) static void sub_update_beacon_observation(struct bt_mesh_subnet *sub) { - sub->beacons_last = sub->beacons_cur; - sub->beacons_cur = 0U; + sub->secure_beacon.last = sub->secure_beacon.cur; + sub->secure_beacon.cur = 0U; + +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + sub->priv_beacon.last = sub->priv_beacon.cur; + sub->priv_beacon.cur = 0U; +#endif } static void update_beacon_observation(void) @@ -357,8 +443,7 @@ static void update_beacon_observation(void) static bool net_beacon_is_running(void) { - return bt_mesh_beacon_enabled() || - atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_INITIATOR) || + return secure_beacon_is_running() || (bt_mesh_priv_beacon_get() == BT_MESH_FEATURE_ENABLED); } @@ -372,7 +457,7 @@ static void beacon_send(struct k_work *work) } update_beacon_observation(); - (void)bt_mesh_subnet_find(net_beacon_send, NULL); + (void)bt_mesh_subnet_find(net_beacon_for_subnet_send, NULL); k_work_schedule(&beacon_timer, PROVISIONED_INTERVAL); return; @@ -389,21 +474,6 @@ static void beacon_send(struct k_work *work) } -struct beacon_params { - union { - const uint8_t *net_id; - struct { - const uint8_t *data; - const uint8_t *random; - } private; - }; - const uint8_t *auth; - uint32_t iv_index; - uint8_t flags; - - bool new_key; -}; - static bool auth_match(struct bt_mesh_subnet_keys *keys, const struct beacon_params *params) { @@ -450,10 +520,8 @@ static bool priv_beacon_decrypt(struct bt_mesh_subnet *sub, void *cb_data) continue; } - err = bt_mesh_beacon_decrypt(sub->keys[i].priv_beacon, - params->private.random, - params->private.data, params->auth, - out); + err = bt_mesh_beacon_decrypt(sub->keys[i].priv_beacon, params->random, + params->data, params->auth, out); if (!err) { params->new_key = (i > 0); params->flags = out[0]; @@ -465,11 +533,12 @@ static bool priv_beacon_decrypt(struct bt_mesh_subnet *sub, void *cb_data) return false; } -static void net_beacon_register(struct bt_mesh_subnet *sub) +static void net_beacon_register(struct bt_mesh_beacon *beacon, bool priv) { - if (bt_mesh_beacon_enabled() && sub->beacons_cur < 0xff) { - sub->beacons_cur++; - sub->beacon_recv = k_uptime_get_32(); + if (((priv && bt_mesh_priv_beacon_get() == BT_MESH_PRIV_GATT_PROXY_ENABLED) || + bt_mesh_beacon_enabled()) && beacon->cur < 0xff) { + beacon->cur++; + beacon->recv = k_uptime_get_32(); } } @@ -505,11 +574,14 @@ static void net_beacon_resolve(struct beacon_params *params, void *cb_data)) { struct bt_mesh_subnet *sub; + struct bt_mesh_beacon *beacon; - sub = bt_mesh_subnet_find(beacon_cache_match, (void *)params->auth); + sub = bt_mesh_subnet_find(beacon_cache_match, (void *)params); if (sub) { + beacon = subnet_beacon_get_by_type(sub, params->private); + /* We've seen this beacon before - just update the stats */ - net_beacon_register(sub); + net_beacon_register(beacon, params->private); return; } @@ -524,10 +596,12 @@ static void net_beacon_resolve(struct beacon_params *params, return; } - cache_add(params->auth, sub); + beacon = subnet_beacon_get_by_type(sub, params->private); + + cache_add(params->auth, beacon); net_beacon_recv(sub, params); - net_beacon_register(sub); + net_beacon_register(beacon, params->private); } static void secure_beacon_recv(struct net_buf_simple *buf) @@ -539,6 +613,7 @@ static void secure_beacon_recv(struct net_buf_simple *buf) return; } + params.private = false; params.flags = net_buf_simple_pull_u8(buf); params.net_id = net_buf_simple_pull_mem(buf, 8); params.iv_index = net_buf_simple_pull_be32(buf); @@ -556,8 +631,9 @@ static void private_beacon_recv(struct net_buf_simple *buf) return; } - params.private.random = net_buf_simple_pull_mem(buf, 13); - params.private.data = net_buf_simple_pull_mem(buf, 5); + params.private = true; + params.random = net_buf_simple_pull_mem(buf, 13); + params.data = net_buf_simple_pull_mem(buf, 5); params.auth = buf->data; net_beacon_resolve(¶ms, priv_beacon_decrypt); @@ -606,11 +682,11 @@ void bt_mesh_beacon_update(struct bt_mesh_subnet *sub) #if defined(CONFIG_BT_MESH_PRIV_BEACONS) /* Invalidate private beacon to force regeneration: */ - sub->priv_beacon.idx = priv_random.idx - 1; + sub->priv_beacon_ctx.idx = priv_random.idx - 1; #endif bt_mesh_beacon_auth(keys->beacon, flags, keys->net_id, bt_mesh.iv_index, - sub->auth); + sub->secure_beacon.auth); } static void subnet_evt(struct bt_mesh_subnet *sub, enum bt_mesh_key_evt evt) @@ -651,8 +727,13 @@ void bt_mesh_beacon_ivu_initiator(bool enable) static void subnet_beacon_enable(struct bt_mesh_subnet *sub) { - sub->beacons_last = 0U; - sub->beacons_cur = 0U; + sub->secure_beacon.last = 0U; + sub->secure_beacon.cur = 0U; + +#if defined(CONFIG_BT_MESH_PRIV_BEACONS) + sub->priv_beacon.last = 0U; + sub->priv_beacon.cur = 0U; +#endif bt_mesh_beacon_update(sub); } diff --git a/subsys/bluetooth/mesh/cfg.c b/subsys/bluetooth/mesh/cfg.c index 7aebd1e8038..13f2bff8051 100644 --- a/subsys/bluetooth/mesh/cfg.c +++ b/subsys/bluetooth/mesh/cfg.c @@ -50,7 +50,7 @@ void bt_mesh_beacon_set(bool beacon) if (beacon) { bt_mesh_beacon_enable(); } else { - bt_mesh_beacon_disable(); + /* Beacon timer will stop automatically when all beacons are disabled. */ } if (IS_ENABLED(CONFIG_BT_SETTINGS) && @@ -104,8 +104,8 @@ int bt_mesh_priv_beacon_set(enum bt_mesh_feat_state priv_beacon) if (priv_beacon == BT_MESH_FEATURE_ENABLED) { bt_mesh_beacon_enable(); - } else if (bt_mesh_beacon_enabled()) { - bt_mesh_beacon_disable(); + } else { + /* Beacon timer will stop automatically when all beacons are disabled. */ } if (IS_ENABLED(CONFIG_BT_SETTINGS) && diff --git a/subsys/bluetooth/mesh/main.c b/subsys/bluetooth/mesh/main.c index 9381a00857e..0ae044035c5 100644 --- a/subsys/bluetooth/mesh/main.c +++ b/subsys/bluetooth/mesh/main.c @@ -401,9 +401,7 @@ int bt_mesh_suspend(void) bt_mesh_hb_suspend(); - if (bt_mesh_beacon_enabled()) { - bt_mesh_beacon_disable(); - } + bt_mesh_beacon_disable(); bt_mesh_model_foreach(model_suspend, NULL); @@ -444,7 +442,8 @@ int bt_mesh_resume(void) bt_mesh_hb_resume(); - if (bt_mesh_beacon_enabled()) { + if (bt_mesh_beacon_enabled() || + bt_mesh_priv_beacon_get() == BT_MESH_PRIV_BEACON_ENABLED) { bt_mesh_beacon_enable(); } @@ -511,10 +510,10 @@ int bt_mesh_start(void) return err; } - if (bt_mesh_beacon_enabled()) { + + if (bt_mesh_beacon_enabled() || + bt_mesh_priv_beacon_get() == BT_MESH_PRIV_BEACON_ENABLED) { bt_mesh_beacon_enable(); - } else { - bt_mesh_beacon_disable(); } if (!IS_ENABLED(CONFIG_BT_MESH_PROV) || !bt_mesh_prov_active() || diff --git a/subsys/bluetooth/mesh/proxy_srv.c b/subsys/bluetooth/mesh/proxy_srv.c index 45276224fb4..b4ac65f41a9 100644 --- a/subsys/bluetooth/mesh/proxy_srv.c +++ b/subsys/bluetooth/mesh/proxy_srv.c @@ -382,7 +382,7 @@ static void identity_enabled(struct bt_mesh_subnet *sub) static void node_id_start(struct bt_mesh_subnet *sub) { #if defined(CONFIG_BT_MESH_PRIV_BEACONS) - sub->priv_beacon.node_id = false; + sub->priv_beacon_ctx.node_id = false; #endif identity_enabled(sub); @@ -391,7 +391,7 @@ static void node_id_start(struct bt_mesh_subnet *sub) static void private_node_id_start(struct bt_mesh_subnet *sub) { #if defined(CONFIG_BT_MESH_PRIV_BEACONS) - sub->priv_beacon.node_id = true; + sub->priv_beacon_ctx.node_id = true; #endif identity_enabled(sub); @@ -752,7 +752,7 @@ static int gatt_proxy_advertise(struct bt_mesh_subnet *sub) LOG_DBG("Node ID active for %u ms, %d ms remaining", active, remaining); #if defined(CONFIG_BT_MESH_PRIV_BEACONS) - priv_node_id = sub->priv_beacon.node_id; + priv_node_id = sub->priv_beacon_ctx.node_id; #endif if (priv_node_id) { err = priv_node_id_adv(sub, remaining); diff --git a/subsys/bluetooth/mesh/subnet.c b/subsys/bluetooth/mesh/subnet.c index a8358b3cbf4..d9ff1a43dcb 100644 --- a/subsys/bluetooth/mesh/subnet.c +++ b/subsys/bluetooth/mesh/subnet.c @@ -612,7 +612,7 @@ uint8_t bt_mesh_subnet_priv_node_id_get(uint16_t net_idx, } #if CONFIG_BT_MESH_GATT_PROXY && CONFIG_BT_MESH_PRIV_BEACONS - if (sub->node_id == BT_MESH_FEATURE_ENABLED && sub->priv_beacon.node_id) { + if (sub->node_id == BT_MESH_FEATURE_ENABLED && sub->priv_beacon_ctx.node_id) { *priv_node_id = sub->node_id; } else { *priv_node_id = BT_MESH_FEATURE_DISABLED; diff --git a/subsys/bluetooth/mesh/subnet.h b/subsys/bluetooth/mesh/subnet.h index 2752c805acf..b34f76227b3 100644 --- a/subsys/bluetooth/mesh/subnet.h +++ b/subsys/bluetooth/mesh/subnet.h @@ -33,19 +33,21 @@ struct bt_mesh_net_cred { uint8_t privacy[16]; /* PrivacyKey */ }; -/** Subnet instance. */ -struct bt_mesh_subnet { - uint32_t beacon_sent; /* Timestamp of last sent beacon */ - uint32_t beacon_recv; /* Timestamp of last received beacon */ - uint8_t beacons_last; /* Number of beacons during last +struct bt_mesh_beacon { + uint32_t sent; /* Timestamp of last sent beacon */ + uint32_t recv; /* Timestamp of last received beacon */ + uint8_t last; /* Number of beacons during last * observation window */ - uint8_t beacons_cur; /* Number of beacons observed during + uint8_t cur; /* Number of beacons observed during * currently ongoing window. */ + uint8_t cache[8]; /* Cached last beacon auth value */ + uint8_t auth[8]; /* Beacon Authentication Value */ +}; - uint8_t beacon_cache[8]; /* Cached last beacon auth value */ - +/** Subnet instance. */ +struct bt_mesh_subnet { uint16_t net_idx; /* NetKeyIndex */ uint8_t kr_phase; /* Key Refresh Phase */ @@ -53,14 +55,16 @@ struct bt_mesh_subnet { uint8_t node_id; /* Node Identity State */ uint32_t node_id_start; /* Node Identity started timestamp */ + struct bt_mesh_beacon secure_beacon; + #if defined(CONFIG_BT_MESH_PRIV_BEACONS) + struct bt_mesh_beacon priv_beacon; struct { uint16_t idx; /* Private beacon random index */ bool node_id; /* Private Node Identity enabled */ uint8_t data[5]; /* Private Beacon data */ - } priv_beacon; + } priv_beacon_ctx; #endif - uint8_t auth[8]; /* Beacon Authentication Value */ struct bt_mesh_subnet_keys { bool valid;