Applied On Fri, 2019-12-13 at 12:15 -0800, Brian Gix wrote: > The daemon handles multiple nodes, that may or may not be on the same > mesh network. While each node my be seperately configured to beacon or > not beacon, there is nothing gained (except redundent traffic) for each > node to beacon seperately. Beaconing is therefore centralized with the > Network Key the SNB represents, with each *received* beacon delivered > to each node. But for SNBs generated, we keep a count of how many nodes > want beacons sent for a specific key. If 1 or more, we beacon, if 0 > nodes want the beacon sent, then we do not beacon. > --- > mesh/mesh-io.c | 3 + > mesh/net-keys.c | 204 +++++++++++++++++++++++++++- > mesh/net-keys.h | 8 ++ > mesh/net.c | 350 ++++++++++++++++-------------------------------- > mesh/net.h | 3 + > 5 files changed, 326 insertions(+), 242 deletions(-) > > diff --git a/mesh/mesh-io.c b/mesh/mesh-io.c > index 95a99b6a5..1ab173d9c 100644 > --- a/mesh/mesh-io.c > +++ b/mesh/mesh-io.c > @@ -171,6 +171,9 @@ bool mesh_io_send(struct mesh_io *io, struct mesh_io_send_info *info, > { > io = l_queue_find(io_list, match_by_io, io); > > + if (!io) > + io = l_queue_peek_head(io_list); > + > if (io && io->api && io->api->send) > return io->api->send(io, info, data, len); > > diff --git a/mesh/net-keys.c b/mesh/net-keys.c > index 5be7e0b58..65f0808dd 100644 > --- a/mesh/net-keys.c > +++ b/mesh/net-keys.c > @@ -23,16 +23,35 @@ > > #include <ell/ell.h> > > +#include "mesh/mesh-defs.h" > +#include "mesh/util.h" > #include "mesh/crypto.h" > +#include "mesh/mesh-io.h" > +#include "mesh/net.h" > #include "mesh/net-keys.h" > > #define BEACON_TYPE_SNB 0x01 > #define KEY_REFRESH 0x01 > #define IV_INDEX_UPDATE 0x02 > > +#define BEACON_INTERVAL_MIN 10 > +#define BEACON_INTERVAL_MAX 600 > + > +struct net_beacon { > + struct l_timeout *timeout; > + uint32_t ts; > + uint16_t observe_period; > + uint16_t observed; > + uint16_t expected; > + bool half_period; > + uint8_t beacon[23]; > +}; > + > struct net_key { > uint32_t id; > + struct net_beacon snb; > uint16_t ref_cnt; > + uint16_t beacon_enables; > uint8_t friend_key; > uint8_t nid; > uint8_t master[16]; > @@ -157,6 +176,7 @@ void net_key_unref(uint32_t id) > > if (key && key->ref_cnt) { > if (--key->ref_cnt == 0) { > + l_timeout_remove(key->snb.timeout); > l_queue_remove(keys, key); > l_free(key); > } > @@ -305,18 +325,188 @@ bool net_key_snb_compose(uint32_t id, uint32_t iv_index, bool kr, bool ivu, > return false; > } > > - snb[0] = BEACON_TYPE_SNB; > - snb[1] = 0; > + snb[0] = MESH_AD_TYPE_BEACON; > + snb[1] = BEACON_TYPE_SNB; > + snb[2] = 0; > > if (kr) > - snb[1] |= KEY_REFRESH; > + snb[2] |= KEY_REFRESH; > > if (ivu) > - snb[1] |= IV_INDEX_UPDATE; > + snb[2] |= IV_INDEX_UPDATE; > > - memcpy(snb + 2, key->network, 8); > - l_put_be32(iv_index, snb + 10); > - l_put_be64(cmac, snb + 14); > + memcpy(snb + 3, key->network, 8); > + l_put_be32(iv_index, snb + 11); > + l_put_be64(cmac, snb + 15); > > return true; > } > + > +static void send_network_beacon(struct net_key *key) > +{ > + struct mesh_io_send_info info = { > + .type = MESH_IO_TIMING_TYPE_GENERAL, > + .u.gen.interval = 100, > + .u.gen.cnt = 1, > + .u.gen.min_delay = DEFAULT_MIN_DELAY, > + .u.gen.max_delay = DEFAULT_MAX_DELAY > + }; > + > + mesh_io_send(NULL, &info, key->snb.beacon, sizeof(key->snb.beacon)); > +} > + > +static void snb_timeout(struct l_timeout *timeout, void *user_data) > +{ > + struct net_key *key = user_data; > + uint32_t interval, scale_factor; > + > + /* Always send at least one beacon */ > + send_network_beacon(key); > + > + /* Count our own beacons towards the vicinity total */ > + key->snb.observed++; > + > + if (!key->snb.half_period) { > + > + l_debug("beacon %d for %d nodes, period %d, obs %d, exp %d", > + key->id, > + key->beacon_enables, > + key->snb.observe_period, > + key->snb.observed, > + key->snb.expected); > + > + > + interval = (key->snb.observe_period * key->snb.observed) > + / key->snb.expected; > + > + /* Limit Increases and Decreases by 10 seconds Up and > + * 20 seconds down each step, to avoid going nearly silent > + * in highly populated environments. > + */ > + if (interval - 10 > key->snb.observe_period) > + interval = key->snb.observe_period + 10; > + else if (interval + 20 < key->snb.observe_period) > + interval = key->snb.observe_period - 20; > + > + /* Beaconing must be no *slower* than once every 10 minutes, > + * and no *faster* than once every 10 seconds, per spec. > + * Observation period is twice beaconing period. > + */ > + if (interval < BEACON_INTERVAL_MIN * 2) > + interval = BEACON_INTERVAL_MIN * 2; > + else if (interval > BEACON_INTERVAL_MAX * 2) > + interval = BEACON_INTERVAL_MAX * 2; > + > + key->snb.observe_period = interval; > + key->snb.observed = 0; > + > + /* To prevent "over slowing" of the beaconing frequency, > + * require more significant "over observing" the slower > + * our own beaconing frequency. > + */ > + key->snb.expected = interval / 10; > + scale_factor = interval / 60; > + key->snb.expected += scale_factor * 3; > + } > + > + interval = key->snb.observe_period / 2; > + key->snb.ts = get_timestamp_secs(); > + key->snb.half_period = !key->snb.half_period; > + > + if (key->beacon_enables) > + l_timeout_modify(timeout, interval); > + else { > + l_timeout_remove(timeout); > + key->snb.timeout = NULL; > + } > +} > + > +void net_key_beacon_seen(uint32_t id) > +{ > + struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); > + > + if (key) > + key->snb.observed++; > +} > + > +void net_key_beacon_enable(uint32_t id) > +{ > + struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); > + bool enabled; > + uint32_t rand_ms; > + > + if (!key) > + return; > + > + enabled = !!key->beacon_enables; > + key->beacon_enables++; > + > + /* If already Enabled, do nothing */ > + if (enabled) > + return; > + > + /* Randomize first timeout to avoid bursts of beacons */ > + l_getrandom(&rand_ms, sizeof(rand_ms)); > + rand_ms %= (BEACON_INTERVAL_MIN * 1000); > + rand_ms++; > + > + /* Enable Periodic Beaconing on this key */ > + key->snb.ts = get_timestamp_secs(); > + key->snb.observe_period = BEACON_INTERVAL_MIN * 2; > + key->snb.expected = 2; > + key->snb.observed = 0; > + key->snb.half_period = true; > + l_timeout_remove(key->snb.timeout); > + key->snb.timeout = l_timeout_create_ms(rand_ms, snb_timeout, key, NULL); > +} > + > +bool net_key_beacon_refresh(uint32_t id, uint32_t iv_index, bool kr, bool ivu) > +{ > + struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); > + uint8_t beacon[23]; > + uint32_t rand_ms; > + > + if (!key) > + return false; > + > + if (!net_key_snb_compose(id, iv_index, kr, ivu, beacon)) > + return false; > + > + if (memcmp(key->snb.beacon, beacon, sizeof(beacon))) > + memcpy(key->snb.beacon, beacon, sizeof(beacon)); > + else > + return false; > + > + l_debug("Setting SNB: IVI: %8.8x, IVU: %d, KR: %d", iv_index, ivu, kr); > + print_packet("Set SNB Beacon to", beacon, sizeof(beacon)); > + > + /* Send one new SNB soon, after all nodes have seen it */ > + l_getrandom(&rand_ms, sizeof(rand_ms)); > + rand_ms %= 1000; > + key->snb.expected++; > + > + if (key->snb.timeout) > + l_timeout_modify_ms(key->snb.timeout, 500 + rand_ms); > + else > + key->snb.timeout = l_timeout_create_ms(500 + rand_ms, > + snb_timeout, key, NULL); > + > + return true; > +} > + > +void net_key_beacon_disable(uint32_t id) > +{ > + struct net_key *key = l_queue_find(keys, match_id, L_UINT_TO_PTR(id)); > + > + if (!key || !key->beacon_enables) > + return; > + > + key->beacon_enables--; > + > + if (key->beacon_enables) > + return; > + > + /* Disable periodic Beaconing on this key */ > + l_timeout_remove(key->snb.timeout); > + key->snb.timeout = NULL; > +} > diff --git a/mesh/net-keys.h b/mesh/net-keys.h > index d54c52156..3c2c4d0da 100644 > --- a/mesh/net-keys.h > +++ b/mesh/net-keys.h > @@ -17,6 +17,10 @@ > * > */ > > +#define BEACON_TYPE_SNB 0x01 > +#define KEY_REFRESH 0x01 > +#define IV_INDEX_UPDATE 0x02 > + > bool net_key_confirm(uint32_t id, const uint8_t master[16]); > bool net_key_retrieve(uint32_t id, uint8_t *master); > uint32_t net_key_add(const uint8_t master[16]); > @@ -31,3 +35,7 @@ bool net_key_snb_check(uint32_t id, uint32_t iv_index, bool kr, bool ivu, > uint64_t cmac); > bool net_key_snb_compose(uint32_t id, uint32_t iv_index, bool kr, bool ivu, > uint8_t *snb); > +void net_key_beacon_seen(uint32_t id); > +void net_key_beacon_enable(uint32_t id); > +bool net_key_beacon_refresh(uint32_t id, uint32_t iv_index, bool kr, bool ivu); > +void net_key_beacon_disable(uint32_t id); > diff --git a/mesh/net.c b/mesh/net.c > index f662d8a91..e708b2aa4 100644 > --- a/mesh/net.c > +++ b/mesh/net.c > @@ -53,15 +53,9 @@ > #define SEG_TO 2 > #define MSG_TO 60 > > -#define DEFAULT_MIN_DELAY 0 > -#define DEFAULT_MAX_DELAY 25 > - > #define DEFAULT_TRANSMIT_COUNT 1 > #define DEFAULT_TRANSMIT_INTERVAL 100 > > -#define BEACON_INTERVAL_MIN 10 > -#define BEACON_INTERVAL_MAX 600 > - > #define SAR_KEY(src, seq0) ((((uint32_t)(seq0)) << 16) | (src)) > > enum _relay_advice { > @@ -90,23 +84,12 @@ struct net_key { > uint8_t network_id[8]; > }; > > -struct mesh_beacon { > - struct l_timeout *timeout; > - uint32_t ts; > - uint16_t observe_period; > - uint16_t observed; > - uint16_t expected; > - uint8_t half_period; > - uint8_t beacon[23]; > -}; > - > struct mesh_subnet { > struct mesh_net *net; > uint16_t idx; > uint32_t net_key_tx; > uint32_t net_key_cur; > uint32_t net_key_upd; > - struct mesh_beacon snb; > uint8_t key_refresh; > uint8_t kr_phase; > }; > @@ -260,8 +243,11 @@ struct net_queue_data { > }; > > struct net_beacon_data { > - const uint8_t *data; > - uint16_t len; > + uint32_t key_id; > + uint32_t ivi; > + bool ivu; > + bool kr; > + bool processed; > }; > > #define FAST_CACHE_SIZE 8 > @@ -570,9 +556,6 @@ static void subnet_free(void *data) > l_free(subnet); > } > > -static void lpn_process_beacon(void *user_data, const void *data, uint8_t size, > - int8_t rssi); > - > static struct mesh_subnet *subnet_new(struct mesh_net *net, uint16_t idx) > { > struct mesh_subnet *subnet; > @@ -583,93 +566,71 @@ static struct mesh_subnet *subnet_new(struct mesh_net *net, uint16_t idx) > > subnet->net = net; > subnet->idx = idx; > - subnet->snb.beacon[0] = MESH_AD_TYPE_BEACON; > return subnet; > } > > -static bool create_secure_beacon(struct mesh_net *net, > - struct mesh_subnet *subnet, > - uint8_t *beacon_data) > +static void enable_beacon(void *a, void *b) > { > - bool kr = (subnet->kr_phase == KEY_REFRESH_PHASE_TWO); > + struct mesh_subnet *subnet = a; > + struct mesh_net *net = b; > > - return net_key_snb_compose(subnet->net_key_tx, net->iv_index, > - kr, net->iv_update, beacon_data); > + if (net->beacon_enable) > + net_key_beacon_enable(subnet->net_key_tx); > + else > + net_key_beacon_disable(subnet->net_key_tx); > } > > -static void send_network_beacon(struct mesh_subnet *subnet, > - struct mesh_net *net) > +static void enqueue_update(void *a, void *b); > + > +static void queue_friend_update(struct mesh_net *net) > { > - struct mesh_io_send_info info = { > - .type = MESH_IO_TIMING_TYPE_GENERAL, > - .u.gen.interval = net->tx_interval, > - .u.gen.cnt = 1, > - .u.gen.min_delay = DEFAULT_MIN_DELAY, > - .u.gen.max_delay = DEFAULT_MAX_DELAY > - }; > + struct mesh_subnet *subnet; > + struct mesh_friend *frnd; > + uint8_t flags = 0; > > - l_info("Send SNB on network %3.3x", subnet->idx); > - mesh_io_send(net->io, &info, subnet->snb.beacon, > - sizeof(subnet->snb.beacon)); > -} > + if (l_queue_length(net->friends)) { > + struct mesh_friend_msg update = { > + .src = net->src_addr, > + .iv_index = mesh_net_get_iv_index(net), > + .last_len = 7, > + .ctl = true, > + }; > > -static void network_beacon_timeout(struct l_timeout *timeout, void *user_data) > -{ > - struct mesh_subnet *subnet = user_data; > - uint32_t interval; > + frnd = l_queue_peek_head(net->friends); > + subnet = l_queue_find(net->subnets, match_key_index, > + L_UINT_TO_PTR(frnd->net_idx)); > > - send_network_beacon(subnet, subnet->net); > + if (!subnet) > + return; > > - if (!subnet->snb.half_period) { > - l_debug("beacon TO period %d, observed %d, expected %d", > - subnet->snb.observe_period, > - subnet->snb.observed, > - subnet->snb.expected); > - interval = subnet->snb.observe_period * > - (subnet->snb.observed + 1) / subnet->snb.expected; > - subnet->snb.observe_period = interval * 2; > - subnet->snb.expected = subnet->snb.observe_period / 10; > - subnet->snb.observed = 0; > - } else > - interval = subnet->snb.observe_period / 2; > + if (subnet->kr_phase == KEY_REFRESH_PHASE_TWO) > + flags |= KEY_REFRESH; > > - if (interval < BEACON_INTERVAL_MIN) > - interval = BEACON_INTERVAL_MIN; > + if (net->iv_update) > + flags |= IV_INDEX_UPDATE; > > - if (interval > BEACON_INTERVAL_MAX) > - interval = BEACON_INTERVAL_MAX; > + update.u.one[0].hdr = NET_OP_FRND_UPDATE << OPCODE_HDR_SHIFT; > + update.u.one[0].seq = mesh_net_next_seq_num(net); > + update.u.one[0].data[0] = NET_OP_FRND_UPDATE; > + update.u.one[0].data[1] = flags; > + l_put_be32(net->iv_index, update.u.one[0].data + 2); > + update.u.one[0].data[6] = 0x01; /* More Data */ > + /* print_packet("Frnd-Beacon-SRC", > + * beacon_data, sizeof(beacon_data)); > + */ > + /* print_packet("Frnd-Update", update.u.one[0].data, 6); */ > > - subnet->snb.ts = get_timestamp_secs(); > - subnet->snb.half_period ^= 1; > - l_timeout_modify(timeout, interval); > + l_queue_foreach(net->friends, enqueue_update, &update); > + } > } > > -static void start_network_beacon(void *a, void *b) > +static void refresh_beacon(void *a, void *b) > { > struct mesh_subnet *subnet = a; > struct mesh_net *net = b; > > - if (!net->beacon_enable) { > - if (subnet->snb.timeout) > - l_timeout_remove(subnet->snb.timeout); > - subnet->snb.timeout = NULL; > - return; > - } > - > - /* If timeout is active, let it run it's course */ > - if (subnet->snb.timeout) > - return; > - > - send_network_beacon(subnet, subnet->net); > - > - subnet->snb.ts = get_timestamp_secs(); > - subnet->snb.expected = 2; > - subnet->snb.observed = 0; > - subnet->snb.half_period = 1; > - subnet->snb.observe_period = BEACON_INTERVAL_MIN * 2; > - > - subnet->snb.timeout = l_timeout_create(BEACON_INTERVAL_MIN, > - network_beacon_timeout, subnet, NULL); > + net_key_beacon_refresh(subnet->net_key_tx, net->iv_index, > + !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), net->iv_update); > } > > struct mesh_net *mesh_net_new(struct mesh_node *node) > @@ -1005,10 +966,11 @@ static struct mesh_subnet *add_key(struct mesh_net *net, uint16_t idx, > return NULL; > } > > - if (!create_secure_beacon(net, subnet, subnet->snb.beacon + 1)) { > - subnet_free(subnet); > - return NULL; > - } > + net_key_beacon_refresh(subnet->net_key_tx, net->iv_index, > + false, net->iv_update); > + > + if (net->beacon_enable) > + net_key_beacon_enable(subnet->net_key_tx); > > l_queue_push_tail(net->subnets, subnet); > > @@ -1043,9 +1005,6 @@ int mesh_net_add_key(struct mesh_net *net, uint16_t idx, const uint8_t *value) > return MESH_STATUS_STORAGE_FAIL; > } > > - if (net->io) > - start_network_beacon(subnet, net); > - > return MESH_STATUS_SUCCESS; > } > > @@ -1072,11 +1031,11 @@ void mesh_net_get_snb_state(struct mesh_net *net, uint8_t *flags, > return; > > *iv_index = net->iv_index; > - *flags = (net->iv_upd_state == IV_UPD_UPDATING) ? 0x02 : 0x00; > + *flags = net->iv_update ? IV_INDEX_UPDATE : 0x00; > > subnet = get_primary_subnet(net); > if (subnet) > - *flags |= subnet->key_refresh ? 0x01 : 0x00; > + *flags |= subnet->key_refresh ? KEY_REFRESH : 0x00; > } > > bool mesh_net_get_key(struct mesh_net *net, bool new_key, uint16_t idx, > @@ -2117,14 +2076,6 @@ static bool ctl_received(struct mesh_net *net, uint16_t key_id, > L_UINT_TO_PTR(src))); > break; > > - case NET_OP_FRND_UPDATE: > - if (ttl) > - return false; > - > - print_packet("Rx-NET_OP_FRND_UPDATE", pkt, len); > - lpn_process_beacon(net, pkt, len, 0); > - break; > - > case NET_OP_FRND_REQUEST: > if (!net->friend_enable) > return false; > @@ -2539,50 +2490,6 @@ static void net_msg_recv(void *user_data, struct mesh_io_recv_info *info, > } > } > > -static void set_network_beacon(void *a, void *b) > -{ > - struct mesh_subnet *subnet = a; > - struct mesh_net *net = b; > - uint8_t beacon_data[22]; > - > - if (!create_secure_beacon(net, subnet, beacon_data)) > - return; > - > - if (memcmp(&subnet->snb.beacon[1], beacon_data, > - sizeof(beacon_data)) == 0) > - return; > - > - memcpy(&subnet->snb.beacon[1], beacon_data, sizeof(beacon_data)); > - > - if (net->beacon_enable && !net->friend_addr) { > - print_packet("Set My Beacon to", > - beacon_data, sizeof(beacon_data)); > - start_network_beacon(subnet, net); > - } > - > - if (l_queue_length(net->friends)) { > - struct mesh_friend_msg update = { > - .src = net->src_addr, > - .iv_index = mesh_net_get_iv_index(net), > - .last_len = 7, > - .ctl = true, > - }; > - > - update.u.one[0].hdr = NET_OP_FRND_UPDATE << OPCODE_HDR_SHIFT; > - update.u.one[0].seq = mesh_net_next_seq_num(net); > - update.u.one[0].data[0] = NET_OP_FRND_UPDATE; > - update.u.one[0].data[1] = beacon_data[3]; > - l_put_be32(net->iv_index, update.u.one[0].data + 2); > - update.u.one[0].data[6] = 0x01; /* More Data */ > - /* print_packet("Frnd-Beacon-SRC", > - * beacon_data, sizeof(beacon_data)); > - */ > - /* print_packet("Frnd-Update", update.u.one[0].data, 6); */ > - > - l_queue_foreach(net->friends, enqueue_update, &update); > - } > -} > - > static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data) > { > struct mesh_net *net = user_data; > @@ -2604,7 +2511,8 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data) > net->iv_update = false; > mesh_config_write_iv_index(node_config_get(net->node), > net->iv_index, false); > - l_queue_foreach(net->subnets, set_network_beacon, net); > + l_queue_foreach(net->subnets, refresh_beacon, net); > + queue_friend_update(net); > mesh_net_flush_msg_queues(net); > break; > > @@ -2646,7 +2554,8 @@ static int key_refresh_phase_two(struct mesh_net *net, uint16_t idx) > * it hears beacons from all the nodes > */ > subnet->kr_phase = KEY_REFRESH_PHASE_TWO; > - set_network_beacon(subnet, net); > + refresh_beacon(subnet, net); > + queue_friend_update(net); > > l_queue_foreach(net->friends, frnd_kr_phase2, net); > > @@ -2679,7 +2588,8 @@ static int key_refresh_finish(struct mesh_net *net, uint16_t idx) > subnet->net_key_upd = 0; > subnet->key_refresh = 0; > subnet->kr_phase = KEY_REFRESH_PHASE_NONE; > - set_network_beacon(subnet, net); > + refresh_beacon(subnet, net); > + queue_friend_update(net); > > l_queue_foreach(net->friends, frnd_kr_phase3, net); > > @@ -2771,106 +2681,73 @@ static void update_iv_ivu_state(struct mesh_net *net, uint32_t iv_index, > static void process_beacon(void *net_ptr, void *user_data) > { > struct mesh_net *net = net_ptr; > - const uint8_t *buf = *(uint8_t **)user_data; > + struct net_beacon_data *beacon_data = user_data; > uint32_t ivi; > bool ivu, kr, local_kr; > struct mesh_subnet *subnet; > - uint32_t key_id; > > - ivi = l_get_be32(buf + 10); > + ivi = beacon_data->ivi; > > /* Ignore out-of-range IV_Index for this network */ > if ((net->iv_index + IV_IDX_DIFF_RANGE < ivi) || (ivi < net->iv_index)) > return; > > - /* Ignore Network IDs unknown to this mesh universe */ > - key_id = net_key_network_id(buf + 2); > - if (!key_id) > - return; > - > + /* Ignore beacons not in this universe */ > subnet = l_queue_find(net->subnets, match_key_id, > - L_UINT_TO_PTR(key_id)); > + L_UINT_TO_PTR(beacon_data->key_id)); > + > if (!subnet) > return; > > /* Get IVU and KR boolean bits from beacon */ > - ivu = !!(buf[1] & 0x02); > - kr = !!(buf[1] & 0x01); > - local_kr = !!(subnet->kr_phase != KEY_REFRESH_PHASE_TWO); > - > - if (net->iv_upd_state != IV_UPD_INIT) { > - /* Ignore beacons that indicate *no change* */ > - if (!memcmp(&subnet->snb.beacon[1], buf, 22)) { > - subnet->snb.observed++; > - return; > - } > - } > - > - /* Validate beacon before accepting */ > - if (!net_key_snb_check(key_id, ivi, kr, ivu, l_get_be64(buf + 14))) { > - l_error("mesh_crypto_beacon verify failed"); > - return; > - } > + ivu = beacon_data->ivu; > + kr = beacon_data->kr; > + local_kr = !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO); > > /* We have officially *seen* this beacon now */ > - subnet->snb.observed++; > - > - update_iv_ivu_state(net, ivi, ivu); > - update_kr_state(subnet, kr, key_id); > - > - if (ivi != net->iv_index || ivu != net->iv_update || kr != local_kr) > - set_network_beacon(subnet, net); > -} > - > -static void lpn_process_beacon(void *user_data, const void *data, > - uint8_t size, int8_t rssi) > -{ > - struct mesh_net *net = user_data; > - const uint8_t *buf = data; > - uint32_t ivi; > - bool ivu, kr, local_kr; > - struct mesh_subnet *subnet; > - bool kr_transition = false; > - > - /* print_packet("lpn: Secure Net Beacon RXed", data, size); */ > - kr = !!(buf[0] & 0x01); > - ivu = !!(buf[0] & 0x02); > - ivi = l_get_be32(buf + 1); > - > - l_debug("KR: %d -- IVU: %d -- IVI: %8.8x", kr, ivu, ivi); > - > - /* TODO: figure out actual network index (i.e., friendship subnet) */ > - subnet = get_primary_subnet(net); > - if (!subnet) > - return; > - > - local_kr = (subnet->kr_phase == KEY_REFRESH_PHASE_TWO); > + beacon_data->processed = true; > > - /* Don't bother going further if nothing has changed */ > - if (local_kr == kr && ivi == net->iv_index && ivu == net->iv_update && > - net->iv_upd_state != IV_UPD_INIT) > + if (ivi == net->iv_index && ivu == net->iv_update && kr == local_kr) > return; > > update_iv_ivu_state(net, ivi, ivu); > - > - if (kr) > - update_kr_state(subnet, kr_transition, subnet->net_key_upd); > - else > - update_kr_state(subnet, kr_transition, subnet->net_key_cur); > + update_kr_state(subnet, kr, beacon_data->key_id); > + net_key_beacon_refresh(beacon_data->key_id, net->iv_index, > + !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), net->iv_update); > } > > static void beacon_recv(void *user_data, struct mesh_io_recv_info *info, > const uint8_t *data, uint16_t len) > { > - const uint8_t *ptr = data + 1; > + struct net_beacon_data beacon_data = { > + .processed = false, > + }; > > if (len != 23 || data[1] != 0x01) > return; > > - l_debug("KR: %d -- IVU: %d -- IV: %8.8x", > - data[2] & 1, !!(data[2] & 2), l_get_be32(data + 11)); > + /* Ignore Network IDs unknown to this daemon */ > + beacon_data.key_id = net_key_network_id(data + 3); > + if (!beacon_data.key_id) > + return; > + > + /* Get data bits from beacon */ > + beacon_data.ivu = !!(data[2] & 0x02); > + beacon_data.kr = !!(data[2] & 0x01); > + beacon_data.ivi = l_get_be32(data + 11); > > - l_queue_foreach(nets, process_beacon, &ptr); > + /* Validate beacon before accepting */ > + if (!net_key_snb_check(beacon_data.key_id, beacon_data.ivi, > + beacon_data.kr, beacon_data.ivu, > + l_get_be64(data + 15))) { > + l_error("mesh_crypto_beacon verify failed"); > + return; > + } > + > + l_queue_foreach(nets, process_beacon, &beacon_data); > + > + if (beacon_data.processed) > + net_key_beacon_seen(beacon_data.key_id); > } > > bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable) > @@ -2878,16 +2755,16 @@ bool mesh_net_set_beacon_mode(struct mesh_net *net, bool enable) > if (!net || !IS_UNASSIGNED(net->friend_addr)) > return false; > > - if (net->beacon_enable != enable) { > - uint8_t type = MESH_AD_TYPE_BEACON; > + if (net->beacon_enable == enable) > + return true; > > - net->beacon_enable = enable; > + net->beacon_enable = enable; > > - if (!enable) > - mesh_io_send_cancel(net->io, &type, 1); > + if (enable) > + l_queue_foreach(net->subnets, refresh_beacon, net); > > - l_queue_foreach(net->subnets, start_network_beacon, net); > - } > + l_queue_foreach(net->subnets, enable_beacon, net); > + queue_friend_update(net); > > return true; > } > @@ -2923,14 +2800,18 @@ bool mesh_net_set_key(struct mesh_net *net, uint16_t idx, const uint8_t *key, > if (phase == KEY_REFRESH_PHASE_TWO) { > subnet->key_refresh = 1; > subnet->net_key_tx = subnet->net_key_upd; > + if (net->beacon_enable) { > + /* Switch beaconing key */ > + net_key_beacon_disable(subnet->net_key_cur); > + net_key_beacon_enable(subnet->net_key_upd); > + } > } > > subnet->kr_phase = phase; > > - set_network_beacon(subnet, net); > + net_key_beacon_refresh(subnet->net_key_tx, net->iv_index, > + !!(subnet->kr_phase == KEY_REFRESH_PHASE_TWO), net->iv_update); > > - if (net->io) > - start_network_beacon(subnet, net); > > return true; > } > @@ -2960,7 +2841,6 @@ bool mesh_net_attach(struct mesh_net *net, struct mesh_io *io) > beacon_recv, NULL); > mesh_io_register_recv_cb(io, MESH_IO_FILTER_NET, > net_msg_recv, NULL); > - l_queue_foreach(net->subnets, start_network_beacon, net); > } > > if (l_queue_find(nets, is_this_net, net)) > @@ -3007,7 +2887,8 @@ bool mesh_net_iv_index_update(struct mesh_net *net) > net->iv_upd_state = IV_UPD_UPDATING; > net->iv_index++; > net->iv_update = true; > - l_queue_foreach(net->subnets, set_network_beacon, net); > + l_queue_foreach(net->subnets, refresh_beacon, net); > + queue_friend_update(net); > net->iv_update_timeout = l_timeout_create( > IV_IDX_UPD_MIN, > iv_upd_to, net, NULL); > @@ -3059,7 +2940,6 @@ bool mesh_net_set_friend(struct mesh_net *net, uint16_t friend_addr) > > net->friend_addr = friend_addr; > > - set_network_beacon(get_primary_subnet(net), net); > return true; > } > > diff --git a/mesh/net.h b/mesh/net.h > index fe4e0b653..90ca8328b 100644 > --- a/mesh/net.h > +++ b/mesh/net.h > @@ -117,6 +117,9 @@ struct mesh_node; > #define FRND_OPCODE(x) \ > ((x) >= NET_OP_FRND_POLL && (x) <= NET_OP_FRND_CLEAR_CONFIRM) > > +#define DEFAULT_MIN_DELAY 0 > +#define DEFAULT_MAX_DELAY 25 > + > struct mesh_net_addr_range { > uint16_t low; > uint16_t high;