Message ID | 20200318170020.1474-1-brian.gix@intel.com (mailing list archive) |
---|---|
State | Accepted |
Delegated to: | Brian Gix |
Headers | show |
Series | [BlueZ,v2] mesh: Allow short messages to be segmented | expand |
Applied On Wed, 2020-03-18 at 10:00 -0700, Brian Gix wrote: > For added reliability, it is legal to send short messages as "single > segment" segmented messages, which require transport layer > acknowledgement. This feature is intended for heavy usage in the future > so I am adding it now. > > Further, to support this functionality, an additional queue has been > added to allow multiple SAR messages to the same DST to be queued and > sent serially. > --- > mesh/cfgmod-server.c | 14 +++---- > mesh/model.c | 12 +++--- > mesh/model.h | 2 +- > mesh/net.c | 90 ++++++++++++++++++++++++++++------------- > mesh/net.h | 6 ++- > mesh/node.c | 8 ++-- > unit/test-mesh-crypto.c | 4 +- > 7 files changed, 86 insertions(+), 50 deletions(-) > > diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c > index 6499c3f2f..1aecab4b5 100644 > --- a/mesh/cfgmod-server.c > +++ b/mesh/cfgmod-server.c > @@ -67,7 +67,7 @@ static void send_pub_status(struct mesh_node *node, uint16_t net_idx, > } > > mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, > - msg, n); > + false, msg, n); > } > > static bool config_pub_get(struct mesh_node *node, uint16_t net_idx, > @@ -211,8 +211,8 @@ static void send_sub_status(struct mesh_node *node, uint16_t net_idx, > n += 2; > } > > - mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, > - DEFAULT_TTL, msg, n); > + mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, > + false, msg, n); > } > > static bool config_sub_get(struct mesh_node *node, uint16_t net_idx, > @@ -272,7 +272,7 @@ static bool config_sub_get(struct mesh_node *node, uint16_t net_idx, > *msg_status = (uint8_t) status; > > mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, > - msg, n); > + false, msg, n); > return true; > } > > @@ -450,7 +450,7 @@ static void send_model_app_status(struct mesh_node *node, uint16_t net_idx, > n += 2; > > mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, > - msg, n); > + false, msg, n); > } > > static void model_app_list(struct mesh_node *node, uint16_t net_idx, > @@ -505,7 +505,7 @@ static void model_app_list(struct mesh_node *node, uint16_t net_idx, > if (result >= 0) { > *status = result; > mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, > - DEFAULT_TTL, msg, n); > + DEFAULT_TTL, false, msg, n); > } > > l_free(msg); > @@ -1234,7 +1234,7 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx, > > if (n) > mesh_model_send(node, dst, src, > - APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, > + APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, false, > long_msg ? long_msg : msg, n); > > l_free(long_msg); > diff --git a/mesh/model.c b/mesh/model.c > index d11c95ab9..945583324 100644 > --- a/mesh/model.c > +++ b/mesh/model.c > @@ -540,7 +540,7 @@ static void cmplt(uint16_t remote, uint8_t status, > > static bool msg_send(struct mesh_node *node, bool credential, uint16_t src, > uint32_t dst, uint16_t app_idx, uint16_t net_idx, > - uint8_t *label, uint8_t ttl, > + uint8_t *label, uint8_t ttl, bool segmented, > const void *msg, uint16_t msg_len) > { > uint8_t dev_key[16]; > @@ -597,8 +597,8 @@ static bool msg_send(struct mesh_node *node, bool credential, uint16_t src, > /* print_packet("Encrypted with", key, 16); */ > > ret = mesh_net_app_send(net, credential, src, dst, key_aid, net_idx, > - ttl, seq_num, iv_index, szmic, out, > - out_len, cmplt, NULL); > + ttl, seq_num, iv_index, segmented, > + szmic, out, out_len, cmplt, NULL); > done: > l_free(out); > return ret; > @@ -1098,14 +1098,14 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id, > > result = msg_send(node, mod->pub->credential != 0, src, > mod->pub->addr, mod->pub->idx, net_idx, > - label, ttl, msg, msg_len); > + label, ttl, false, msg, msg_len); > > return result ? MESH_ERROR_NONE : MESH_ERROR_FAILED; > } > > bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst, > uint16_t app_idx, uint16_t net_idx, > - uint8_t ttl, > + uint8_t ttl, bool segmented, > const void *msg, uint16_t msg_len) > { > /* print_packet("Mod Tx", msg, msg_len); */ > @@ -1120,7 +1120,7 @@ bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst, > return false; > > return msg_send(node, false, src, dst, app_idx, net_idx, > - NULL, ttl, msg, msg_len); > + NULL, ttl, segmented, msg, msg_len); > } > > int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id, > diff --git a/mesh/model.h b/mesh/model.h > index 153ab9bfd..f8e0f9d37 100644 > --- a/mesh/model.h > +++ b/mesh/model.h > @@ -95,7 +95,7 @@ int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id, > uint16_t mesh_model_cfg_blk(uint8_t *pkt); > bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst, > uint16_t app_idx, uint16_t net_idx, > - uint8_t ttl, > + uint8_t ttl, bool segmented, > const void *msg, uint16_t msg_len); > int mesh_model_publish(struct mesh_node *node, uint32_t mod_id, uint16_t src, > uint8_t ttl, const void *msg, uint16_t msg_len); > diff --git a/mesh/net.c b/mesh/net.c > index d3325e073..55b1330cc 100644 > --- a/mesh/net.c > +++ b/mesh/net.c > @@ -139,6 +139,7 @@ struct mesh_net { > struct l_queue *replay_cache; > struct l_queue *sar_in; > struct l_queue *sar_out; > + struct l_queue *sar_queue; > struct l_queue *frnd_msgs; > struct l_queue *friends; > struct l_queue *negotiations; > @@ -182,6 +183,7 @@ struct mesh_sar { > uint16_t remote; > uint16_t len; > bool szmic; > + bool segmented; > bool frnd; > bool frnd_cred; > uint8_t ttl; > @@ -662,6 +664,7 @@ struct mesh_net *mesh_net_new(struct mesh_node *node) > net->msg_cache = l_queue_new(); > net->sar_in = l_queue_new(); > net->sar_out = l_queue_new(); > + net->sar_queue = l_queue_new(); > net->frnd_msgs = l_queue_new(); > net->destinations = l_queue_new(); > net->app_keys = l_queue_new(); > @@ -687,6 +690,7 @@ void mesh_net_free(struct mesh_net *net) > l_queue_destroy(net->replay_cache, l_free); > l_queue_destroy(net->sar_in, mesh_sar_free); > l_queue_destroy(net->sar_out, mesh_sar_free); > + l_queue_destroy(net->sar_queue, mesh_sar_free); > l_queue_destroy(net->frnd_msgs, l_free); > l_queue_destroy(net->friends, mesh_friend_free); > l_queue_destroy(net->negotiations, mesh_friend_free); > @@ -1657,6 +1661,22 @@ static void outmsg_to(struct l_timeout *msg_timeout, void *user_data) > } > > static void outseg_to(struct l_timeout *seg_timeout, void *user_data); > + > +static void send_queued_sar(struct mesh_net *net, uint16_t dst) > +{ > + struct mesh_sar *sar = l_queue_remove_if(net->sar_queue, > + match_sar_remote, L_UINT_TO_PTR(dst)); > + > + if (!sar) > + return; > + > + /* Out to current outgoing, and immediate expire Seg TO */ > + l_queue_push_head(net->sar_out, sar); > + sar->seg_timeout = NULL; > + sar->msg_timeout = l_timeout_create(MSG_TO, outmsg_to, net, NULL); > + outseg_to(NULL, net); > +} > + > static void ack_received(struct mesh_net *net, bool timeout, > uint16_t src, uint16_t dst, > uint16_t seq0, uint32_t ack_flag) > @@ -1692,6 +1712,7 @@ static void ack_received(struct mesh_net *net, bool timeout, > outgoing->len - 4, outgoing->user_data); > > l_queue_remove(net->sar_out, outgoing); > + send_queued_sar(net, outgoing->remote); > mesh_sar_free(outgoing); > > return; > @@ -1701,10 +1722,10 @@ static void ack_received(struct mesh_net *net, bool timeout, > > ack_copy &= outgoing->flags; > > - for (i = 0; i <= SEG_MAX(outgoing->len); i++, seg_flag <<= 1) { > + for (i = 0; i <= SEG_MAX(true, outgoing->len); i++, seg_flag <<= 1) { > if (seg_flag & ack_flag) { > l_debug("Skipping Seg %d of %d", > - i, SEG_MAX(outgoing->len)); > + i, SEG_MAX(true, outgoing->len)); > continue; > } > > @@ -1741,7 +1762,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, > uint8_t ttl, uint32_t seq, > uint16_t net_idx, > uint16_t src, uint16_t dst, > - uint8_t key_aid, > + uint8_t key_aid, bool segmented, > bool szmic, uint16_t seqZero, > const uint8_t *data, uint16_t size) > { > @@ -1768,7 +1789,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, > hdr |= true << SEG_HDR_SHIFT; > hdr |= szmic << SZMIC_HDR_SHIFT; > hdr |= (seqZero & SEQ_ZERO_MASK) << SEQ_ZERO_HDR_SHIFT; > - hdr |= SEG_MAX(size) << SEGN_HDR_SHIFT; > + hdr |= SEG_MAX(true, size) << SEGN_HDR_SHIFT; > } > > if (friend_packet_queue(net, iv_index, false, frnd_ttl, > @@ -1967,7 +1988,7 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, > l_info("RXed (old: %04x %06x size:%d) %d of %d", > seqZero, seq, size, segO, segN); > /* Sanity Check--> certain things must match */ > - if (SEG_MAX(sar_in->len) != segN || > + if (SEG_MAX(true, sar_in->len) != segN || > sar_in->key_aid != key_aid) > return false; > > @@ -2022,8 +2043,8 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, > > msg_rxed(net, frnd, iv_index, ttl, seq, net_idx, > sar_in->remote, dst, > - key_aid, > - szmic, sar_in->seqZero, > + key_aid, true, szmic, > + sar_in->seqZero, > sar_in->buf, sar_in->len); > > /* Kill Inter-Seg timeout */ > @@ -2426,7 +2447,8 @@ static enum _relay_advice packet_received(void *user_data, > net_idx, > net_src, net_dst, > net_key_id, > - false, net_seq & SEQ_ZERO_MASK, > + false, false, > + net_seq & SEQ_ZERO_MASK, > msg, app_msg_len); > } > > @@ -2539,7 +2561,8 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data) > > switch (net->iv_upd_state) { > case IV_UPD_UPDATING: > - if (l_queue_length(net->sar_out)) { > + if (l_queue_length(net->sar_out) || > + l_queue_length(net->sar_queue)) { > l_info("don't leave IV Update until sar_out empty"); > l_timeout_modify(net->iv_update_timeout, 10); > break; > @@ -3043,12 +3066,12 @@ static bool send_seg(struct mesh_net *net, struct mesh_sar *msg, uint8_t segO) > uint8_t gatt_data[30]; > uint8_t *packet = gatt_data; > uint8_t packet_len; > - uint8_t segN = SEG_MAX(msg->len); > + uint8_t segN = SEG_MAX(msg->segmented, msg->len); > uint16_t seg_off = SEG_OFF(segO); > uint32_t key_id = 0; > uint32_t seq_num; > > - if (segN) { > + if (msg->segmented) { > /* Send each segment on unique seq_num */ > seq_num = mesh_net_next_seq_num(net); > > @@ -3075,7 +3098,7 @@ static bool send_seg(struct mesh_net *net, struct mesh_sar *msg, uint8_t segO) > seq_num, > msg->src, msg->remote, > 0, > - segN ? true : false, msg->key_aid, > + msg->segmented, msg->key_aid, > msg->szmic, false, msg->seqZero, > segO, segN, > msg->buf + seg_off, seg_len, > @@ -3169,7 +3192,8 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id, > bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, > uint16_t dst, uint8_t key_aid, uint16_t net_idx, > uint8_t ttl, uint32_t seq, uint32_t iv_index, > - bool szmic, const void *msg, uint16_t msg_len, > + bool segmented, bool szmic, > + const void *msg, uint16_t msg_len, > mesh_net_status_func_t status_func, > void *user_data) > { > @@ -3189,14 +3213,17 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, > if (ttl == DEFAULT_TTL) > ttl = net->default_ttl; > > - seg_max = SEG_MAX(msg_len); > + /* Long and sizmic messages *require* segmenting */ > + segmented |= szmic; > + seg_max = SEG_MAX(segmented, msg_len); > + segmented |= !!(seg_max); > > /* First enqueue to any Friends and internal models */ > result = msg_rxed(net, false, iv_index, ttl, > seq, > net_idx, > src, dst, > - key_aid, > + key_aid, segmented, > szmic, seq & SEQ_ZERO_MASK, > msg, msg_len); > > @@ -3207,13 +3234,6 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, > (dst >= net->src_addr && dst <= net->last_addr)) > return true; > > - /* If Segmented, Cancel any OB segmented message to same DST */ > - if (seg_max) { > - payload = l_queue_remove_if(net->sar_out, match_sar_remote, > - L_UINT_TO_PTR(dst)); > - mesh_sar_free(payload); > - } > - > /* Setup OTA Network send */ > payload = mesh_sar_new(msg_len); > memcpy(payload->buf, msg, msg_len); > @@ -3224,16 +3244,30 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, > payload->szmic = szmic; > payload->frnd_cred = frnd_cred; > payload->key_aid = key_aid; > - if (seg_max) { > + payload->iv_index = mesh_net_get_iv_index(net); > + payload->seqAuth = seq; > + payload->segmented = segmented; > + if (segmented) { > payload->flags = 0xffffffff >> (31 - seg_max); > payload->seqZero = seq & SEQ_ZERO_MASK; > - } > + payload->status_func = status_func; > + payload->user_data = user_data; > + payload->id = ++net->sar_id_next; > > - payload->iv_index = mesh_net_get_iv_index(net); > - payload->seqAuth = seq; > + /* Single thread SAR messages to same Unicast DST */ > + if (NULL != l_queue_find(net->sar_out, match_sar_remote, > + L_UINT_TO_PTR(dst))) { > + /* Delay sending Outbound SAR unless prior > + * SAR to same DST has completed */ > + > + l_info("OB-Queued SeqZero: %4.4x", payload->seqZero); > + l_queue_push_tail(net->sar_queue, payload); > + return true; > + } > + } > > result = true; > - if (!IS_UNICAST(dst) && seg_max) { > + if (!IS_UNICAST(dst) && segmented) { > int i; > > for (i = 0; i < 4; i++) { > @@ -3246,7 +3280,7 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, > } > > /* Reliable: Cache; Unreliable: Flush*/ > - if (result && seg_max && IS_UNICAST(dst)) { > + if (result && segmented && IS_UNICAST(dst)) { > l_queue_push_head(net->sar_out, payload); > payload->seg_timeout = > l_timeout_create(SEG_TO, outseg_to, net, NULL); > diff --git a/mesh/net.h b/mesh/net.h > index 6fedd69d7..cb90c1d92 100644 > --- a/mesh/net.h > +++ b/mesh/net.h > @@ -40,8 +40,9 @@ struct mesh_node; > > #define MAX_UNSEG_LEN 15 /* msg_len == 11 + sizeof(MIC) */ > #define MAX_SEG_LEN 12 /* UnSeg length - 3 octets overhead */ > -#define SEG_MAX(len) (((len) <= MAX_UNSEG_LEN) ? 0 : \ > +#define SEG_MAX(seg, len) ((!seg && len <= MAX_UNSEG_LEN) ? 0 : \ > (((len) - 1) / MAX_SEG_LEN)) > + > #define SEG_OFF(seg) ((seg) * MAX_SEG_LEN) > #define MAX_SEG_TO_LEN(seg) ((seg) ? SEG_OFF((seg) + 1) : MAX_UNSEG_LEN) > > @@ -311,7 +312,8 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id, > bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, > uint16_t dst, uint8_t key_id, uint16_t net_idx, > uint8_t ttl, uint32_t seq, uint32_t iv_index, > - bool szmic, const void *msg, uint16_t msg_len, > + bool segmented, bool szmic, > + const void *msg, uint16_t msg_len, > mesh_net_status_func_t status_func, > void *user_data); > void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id, > diff --git a/mesh/node.c b/mesh/node.c > index d4be070fa..acda6d472 100644 > --- a/mesh/node.c > +++ b/mesh/node.c > @@ -1830,7 +1830,7 @@ static struct l_dbus_message *send_call(struct l_dbus *dbus, > return dbus_error(msg, MESH_ERROR_INVALID_ARGS, > "Invalid key_index"); > > - if (!mesh_model_send(node, src, dst, app_idx, 0, DEFAULT_TTL, > + if (!mesh_model_send(node, src, dst, app_idx, 0, DEFAULT_TTL, false, > data, len)) > return dbus_error(msg, MESH_ERROR_FAILED, NULL); > > @@ -1879,7 +1879,7 @@ static struct l_dbus_message *dev_key_send_call(struct l_dbus *dbus, > > app_idx = remote ? APP_IDX_DEV_REMOTE : APP_IDX_DEV_LOCAL; > if (!mesh_model_send(node, src, dst, app_idx, net_idx, DEFAULT_TTL, > - data, len)) > + false, data, len)) > return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL); > > return l_dbus_message_new_method_return(msg); > @@ -1937,7 +1937,7 @@ static struct l_dbus_message *add_netkey_call(struct l_dbus *dbus, > l_put_le16(sub_idx, &data[2]); > > if (!mesh_model_send(node, src, dst, APP_IDX_DEV_REMOTE, net_idx, > - DEFAULT_TTL, data, 20)) > + DEFAULT_TTL, false, data, 20)) > return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL); > > return l_dbus_message_new_method_return(msg); > @@ -2003,7 +2003,7 @@ static struct l_dbus_message *add_appkey_call(struct l_dbus *dbus, > data[3] = app_idx >> 4; > > if (!mesh_model_send(node, src, dst, APP_IDX_DEV_REMOTE, net_idx, > - DEFAULT_TTL, data, 20)) > + DEFAULT_TTL, false, data, 20)) > return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL); > > return l_dbus_message_new_method_return(msg); > diff --git a/unit/test-mesh-crypto.c b/unit/test-mesh-crypto.c > index 32c46a54e..0043b0b10 100644 > --- a/unit/test-mesh-crypto.c > +++ b/unit/test-mesh-crypto.c > @@ -1017,7 +1017,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) > app_msg = l_util_from_hexstring(keys->app_msg, &app_msg_len); > > if (keys->szmic) { > - seg_max = SEG_MAX(app_msg_len + 8); > + seg_max = SEG_MAX(keys->segmented, app_msg_len + 8); > enc_msg = l_malloc(app_msg_len + 8); > mesh_crypto_application_encrypt(key_aid, keys->app_seq, > keys->net_src, keys->net_dst, > @@ -1028,7 +1028,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) > enc_msg, &app_mic64, sizeof(app_mic64)); > l_put_be64(app_mic64, enc_msg + app_msg_len); > } else { > - seg_max = SEG_MAX(app_msg_len + 4); > + seg_max = SEG_MAX(keys->segmented, app_msg_len + 4); > enc_msg = l_malloc(app_msg_len + 4); > mesh_crypto_application_encrypt(key_aid, keys->app_seq, > keys->net_src, keys->net_dst,
diff --git a/mesh/cfgmod-server.c b/mesh/cfgmod-server.c index 6499c3f2f..1aecab4b5 100644 --- a/mesh/cfgmod-server.c +++ b/mesh/cfgmod-server.c @@ -67,7 +67,7 @@ static void send_pub_status(struct mesh_node *node, uint16_t net_idx, } mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, - msg, n); + false, msg, n); } static bool config_pub_get(struct mesh_node *node, uint16_t net_idx, @@ -211,8 +211,8 @@ static void send_sub_status(struct mesh_node *node, uint16_t net_idx, n += 2; } - mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, - DEFAULT_TTL, msg, n); + mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, + false, msg, n); } static bool config_sub_get(struct mesh_node *node, uint16_t net_idx, @@ -272,7 +272,7 @@ static bool config_sub_get(struct mesh_node *node, uint16_t net_idx, *msg_status = (uint8_t) status; mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, - msg, n); + false, msg, n); return true; } @@ -450,7 +450,7 @@ static void send_model_app_status(struct mesh_node *node, uint16_t net_idx, n += 2; mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, - msg, n); + false, msg, n); } static void model_app_list(struct mesh_node *node, uint16_t net_idx, @@ -505,7 +505,7 @@ static void model_app_list(struct mesh_node *node, uint16_t net_idx, if (result >= 0) { *status = result; mesh_model_send(node, dst, src, APP_IDX_DEV_LOCAL, net_idx, - DEFAULT_TTL, msg, n); + DEFAULT_TTL, false, msg, n); } l_free(msg); @@ -1234,7 +1234,7 @@ static bool cfg_srv_pkt(uint16_t src, uint16_t dst, uint16_t app_idx, if (n) mesh_model_send(node, dst, src, - APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, + APP_IDX_DEV_LOCAL, net_idx, DEFAULT_TTL, false, long_msg ? long_msg : msg, n); l_free(long_msg); diff --git a/mesh/model.c b/mesh/model.c index d11c95ab9..945583324 100644 --- a/mesh/model.c +++ b/mesh/model.c @@ -540,7 +540,7 @@ static void cmplt(uint16_t remote, uint8_t status, static bool msg_send(struct mesh_node *node, bool credential, uint16_t src, uint32_t dst, uint16_t app_idx, uint16_t net_idx, - uint8_t *label, uint8_t ttl, + uint8_t *label, uint8_t ttl, bool segmented, const void *msg, uint16_t msg_len) { uint8_t dev_key[16]; @@ -597,8 +597,8 @@ static bool msg_send(struct mesh_node *node, bool credential, uint16_t src, /* print_packet("Encrypted with", key, 16); */ ret = mesh_net_app_send(net, credential, src, dst, key_aid, net_idx, - ttl, seq_num, iv_index, szmic, out, - out_len, cmplt, NULL); + ttl, seq_num, iv_index, segmented, + szmic, out, out_len, cmplt, NULL); done: l_free(out); return ret; @@ -1098,14 +1098,14 @@ int mesh_model_publish(struct mesh_node *node, uint32_t mod_id, result = msg_send(node, mod->pub->credential != 0, src, mod->pub->addr, mod->pub->idx, net_idx, - label, ttl, msg, msg_len); + label, ttl, false, msg, msg_len); return result ? MESH_ERROR_NONE : MESH_ERROR_FAILED; } bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst, uint16_t app_idx, uint16_t net_idx, - uint8_t ttl, + uint8_t ttl, bool segmented, const void *msg, uint16_t msg_len) { /* print_packet("Mod Tx", msg, msg_len); */ @@ -1120,7 +1120,7 @@ bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst, return false; return msg_send(node, false, src, dst, app_idx, net_idx, - NULL, ttl, msg, msg_len); + NULL, ttl, segmented, msg, msg_len); } int mesh_model_pub_set(struct mesh_node *node, uint16_t addr, uint32_t id, diff --git a/mesh/model.h b/mesh/model.h index 153ab9bfd..f8e0f9d37 100644 --- a/mesh/model.h +++ b/mesh/model.h @@ -95,7 +95,7 @@ int mesh_model_sub_get(struct mesh_node *node, uint16_t addr, uint32_t id, uint16_t mesh_model_cfg_blk(uint8_t *pkt); bool mesh_model_send(struct mesh_node *node, uint16_t src, uint16_t dst, uint16_t app_idx, uint16_t net_idx, - uint8_t ttl, + uint8_t ttl, bool segmented, const void *msg, uint16_t msg_len); int mesh_model_publish(struct mesh_node *node, uint32_t mod_id, uint16_t src, uint8_t ttl, const void *msg, uint16_t msg_len); diff --git a/mesh/net.c b/mesh/net.c index d3325e073..55b1330cc 100644 --- a/mesh/net.c +++ b/mesh/net.c @@ -139,6 +139,7 @@ struct mesh_net { struct l_queue *replay_cache; struct l_queue *sar_in; struct l_queue *sar_out; + struct l_queue *sar_queue; struct l_queue *frnd_msgs; struct l_queue *friends; struct l_queue *negotiations; @@ -182,6 +183,7 @@ struct mesh_sar { uint16_t remote; uint16_t len; bool szmic; + bool segmented; bool frnd; bool frnd_cred; uint8_t ttl; @@ -662,6 +664,7 @@ struct mesh_net *mesh_net_new(struct mesh_node *node) net->msg_cache = l_queue_new(); net->sar_in = l_queue_new(); net->sar_out = l_queue_new(); + net->sar_queue = l_queue_new(); net->frnd_msgs = l_queue_new(); net->destinations = l_queue_new(); net->app_keys = l_queue_new(); @@ -687,6 +690,7 @@ void mesh_net_free(struct mesh_net *net) l_queue_destroy(net->replay_cache, l_free); l_queue_destroy(net->sar_in, mesh_sar_free); l_queue_destroy(net->sar_out, mesh_sar_free); + l_queue_destroy(net->sar_queue, mesh_sar_free); l_queue_destroy(net->frnd_msgs, l_free); l_queue_destroy(net->friends, mesh_friend_free); l_queue_destroy(net->negotiations, mesh_friend_free); @@ -1657,6 +1661,22 @@ static void outmsg_to(struct l_timeout *msg_timeout, void *user_data) } static void outseg_to(struct l_timeout *seg_timeout, void *user_data); + +static void send_queued_sar(struct mesh_net *net, uint16_t dst) +{ + struct mesh_sar *sar = l_queue_remove_if(net->sar_queue, + match_sar_remote, L_UINT_TO_PTR(dst)); + + if (!sar) + return; + + /* Out to current outgoing, and immediate expire Seg TO */ + l_queue_push_head(net->sar_out, sar); + sar->seg_timeout = NULL; + sar->msg_timeout = l_timeout_create(MSG_TO, outmsg_to, net, NULL); + outseg_to(NULL, net); +} + static void ack_received(struct mesh_net *net, bool timeout, uint16_t src, uint16_t dst, uint16_t seq0, uint32_t ack_flag) @@ -1692,6 +1712,7 @@ static void ack_received(struct mesh_net *net, bool timeout, outgoing->len - 4, outgoing->user_data); l_queue_remove(net->sar_out, outgoing); + send_queued_sar(net, outgoing->remote); mesh_sar_free(outgoing); return; @@ -1701,10 +1722,10 @@ static void ack_received(struct mesh_net *net, bool timeout, ack_copy &= outgoing->flags; - for (i = 0; i <= SEG_MAX(outgoing->len); i++, seg_flag <<= 1) { + for (i = 0; i <= SEG_MAX(true, outgoing->len); i++, seg_flag <<= 1) { if (seg_flag & ack_flag) { l_debug("Skipping Seg %d of %d", - i, SEG_MAX(outgoing->len)); + i, SEG_MAX(true, outgoing->len)); continue; } @@ -1741,7 +1762,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, uint8_t ttl, uint32_t seq, uint16_t net_idx, uint16_t src, uint16_t dst, - uint8_t key_aid, + uint8_t key_aid, bool segmented, bool szmic, uint16_t seqZero, const uint8_t *data, uint16_t size) { @@ -1768,7 +1789,7 @@ static bool msg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, hdr |= true << SEG_HDR_SHIFT; hdr |= szmic << SZMIC_HDR_SHIFT; hdr |= (seqZero & SEQ_ZERO_MASK) << SEQ_ZERO_HDR_SHIFT; - hdr |= SEG_MAX(size) << SEGN_HDR_SHIFT; + hdr |= SEG_MAX(true, size) << SEGN_HDR_SHIFT; } if (friend_packet_queue(net, iv_index, false, frnd_ttl, @@ -1967,7 +1988,7 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, l_info("RXed (old: %04x %06x size:%d) %d of %d", seqZero, seq, size, segO, segN); /* Sanity Check--> certain things must match */ - if (SEG_MAX(sar_in->len) != segN || + if (SEG_MAX(true, sar_in->len) != segN || sar_in->key_aid != key_aid) return false; @@ -2022,8 +2043,8 @@ static bool seg_rxed(struct mesh_net *net, bool frnd, uint32_t iv_index, msg_rxed(net, frnd, iv_index, ttl, seq, net_idx, sar_in->remote, dst, - key_aid, - szmic, sar_in->seqZero, + key_aid, true, szmic, + sar_in->seqZero, sar_in->buf, sar_in->len); /* Kill Inter-Seg timeout */ @@ -2426,7 +2447,8 @@ static enum _relay_advice packet_received(void *user_data, net_idx, net_src, net_dst, net_key_id, - false, net_seq & SEQ_ZERO_MASK, + false, false, + net_seq & SEQ_ZERO_MASK, msg, app_msg_len); } @@ -2539,7 +2561,8 @@ static void iv_upd_to(struct l_timeout *upd_timeout, void *user_data) switch (net->iv_upd_state) { case IV_UPD_UPDATING: - if (l_queue_length(net->sar_out)) { + if (l_queue_length(net->sar_out) || + l_queue_length(net->sar_queue)) { l_info("don't leave IV Update until sar_out empty"); l_timeout_modify(net->iv_update_timeout, 10); break; @@ -3043,12 +3066,12 @@ static bool send_seg(struct mesh_net *net, struct mesh_sar *msg, uint8_t segO) uint8_t gatt_data[30]; uint8_t *packet = gatt_data; uint8_t packet_len; - uint8_t segN = SEG_MAX(msg->len); + uint8_t segN = SEG_MAX(msg->segmented, msg->len); uint16_t seg_off = SEG_OFF(segO); uint32_t key_id = 0; uint32_t seq_num; - if (segN) { + if (msg->segmented) { /* Send each segment on unique seq_num */ seq_num = mesh_net_next_seq_num(net); @@ -3075,7 +3098,7 @@ static bool send_seg(struct mesh_net *net, struct mesh_sar *msg, uint8_t segO) seq_num, msg->src, msg->remote, 0, - segN ? true : false, msg->key_aid, + msg->segmented, msg->key_aid, msg->szmic, false, msg->seqZero, segO, segN, msg->buf + seg_off, seg_len, @@ -3169,7 +3192,8 @@ void mesh_net_send_seg(struct mesh_net *net, uint32_t net_key_id, bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, uint16_t dst, uint8_t key_aid, uint16_t net_idx, uint8_t ttl, uint32_t seq, uint32_t iv_index, - bool szmic, const void *msg, uint16_t msg_len, + bool segmented, bool szmic, + const void *msg, uint16_t msg_len, mesh_net_status_func_t status_func, void *user_data) { @@ -3189,14 +3213,17 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, if (ttl == DEFAULT_TTL) ttl = net->default_ttl; - seg_max = SEG_MAX(msg_len); + /* Long and sizmic messages *require* segmenting */ + segmented |= szmic; + seg_max = SEG_MAX(segmented, msg_len); + segmented |= !!(seg_max); /* First enqueue to any Friends and internal models */ result = msg_rxed(net, false, iv_index, ttl, seq, net_idx, src, dst, - key_aid, + key_aid, segmented, szmic, seq & SEQ_ZERO_MASK, msg, msg_len); @@ -3207,13 +3234,6 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, (dst >= net->src_addr && dst <= net->last_addr)) return true; - /* If Segmented, Cancel any OB segmented message to same DST */ - if (seg_max) { - payload = l_queue_remove_if(net->sar_out, match_sar_remote, - L_UINT_TO_PTR(dst)); - mesh_sar_free(payload); - } - /* Setup OTA Network send */ payload = mesh_sar_new(msg_len); memcpy(payload->buf, msg, msg_len); @@ -3224,16 +3244,30 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, payload->szmic = szmic; payload->frnd_cred = frnd_cred; payload->key_aid = key_aid; - if (seg_max) { + payload->iv_index = mesh_net_get_iv_index(net); + payload->seqAuth = seq; + payload->segmented = segmented; + if (segmented) { payload->flags = 0xffffffff >> (31 - seg_max); payload->seqZero = seq & SEQ_ZERO_MASK; - } + payload->status_func = status_func; + payload->user_data = user_data; + payload->id = ++net->sar_id_next; - payload->iv_index = mesh_net_get_iv_index(net); - payload->seqAuth = seq; + /* Single thread SAR messages to same Unicast DST */ + if (NULL != l_queue_find(net->sar_out, match_sar_remote, + L_UINT_TO_PTR(dst))) { + /* Delay sending Outbound SAR unless prior + * SAR to same DST has completed */ + + l_info("OB-Queued SeqZero: %4.4x", payload->seqZero); + l_queue_push_tail(net->sar_queue, payload); + return true; + } + } result = true; - if (!IS_UNICAST(dst) && seg_max) { + if (!IS_UNICAST(dst) && segmented) { int i; for (i = 0; i < 4; i++) { @@ -3246,7 +3280,7 @@ bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, } /* Reliable: Cache; Unreliable: Flush*/ - if (result && seg_max && IS_UNICAST(dst)) { + if (result && segmented && IS_UNICAST(dst)) { l_queue_push_head(net->sar_out, payload); payload->seg_timeout = l_timeout_create(SEG_TO, outseg_to, net, NULL); diff --git a/mesh/net.h b/mesh/net.h index 6fedd69d7..cb90c1d92 100644 --- a/mesh/net.h +++ b/mesh/net.h @@ -40,8 +40,9 @@ struct mesh_node; #define MAX_UNSEG_LEN 15 /* msg_len == 11 + sizeof(MIC) */ #define MAX_SEG_LEN 12 /* UnSeg length - 3 octets overhead */ -#define SEG_MAX(len) (((len) <= MAX_UNSEG_LEN) ? 0 : \ +#define SEG_MAX(seg, len) ((!seg && len <= MAX_UNSEG_LEN) ? 0 : \ (((len) - 1) / MAX_SEG_LEN)) + #define SEG_OFF(seg) ((seg) * MAX_SEG_LEN) #define MAX_SEG_TO_LEN(seg) ((seg) ? SEG_OFF((seg) + 1) : MAX_UNSEG_LEN) @@ -311,7 +312,8 @@ void mesh_net_transport_send(struct mesh_net *net, uint32_t key_id, bool mesh_net_app_send(struct mesh_net *net, bool frnd_cred, uint16_t src, uint16_t dst, uint8_t key_id, uint16_t net_idx, uint8_t ttl, uint32_t seq, uint32_t iv_index, - bool szmic, const void *msg, uint16_t msg_len, + bool segmented, bool szmic, + const void *msg, uint16_t msg_len, mesh_net_status_func_t status_func, void *user_data); void mesh_net_ack_send(struct mesh_net *net, uint32_t key_id, diff --git a/mesh/node.c b/mesh/node.c index d4be070fa..acda6d472 100644 --- a/mesh/node.c +++ b/mesh/node.c @@ -1830,7 +1830,7 @@ static struct l_dbus_message *send_call(struct l_dbus *dbus, return dbus_error(msg, MESH_ERROR_INVALID_ARGS, "Invalid key_index"); - if (!mesh_model_send(node, src, dst, app_idx, 0, DEFAULT_TTL, + if (!mesh_model_send(node, src, dst, app_idx, 0, DEFAULT_TTL, false, data, len)) return dbus_error(msg, MESH_ERROR_FAILED, NULL); @@ -1879,7 +1879,7 @@ static struct l_dbus_message *dev_key_send_call(struct l_dbus *dbus, app_idx = remote ? APP_IDX_DEV_REMOTE : APP_IDX_DEV_LOCAL; if (!mesh_model_send(node, src, dst, app_idx, net_idx, DEFAULT_TTL, - data, len)) + false, data, len)) return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL); return l_dbus_message_new_method_return(msg); @@ -1937,7 +1937,7 @@ static struct l_dbus_message *add_netkey_call(struct l_dbus *dbus, l_put_le16(sub_idx, &data[2]); if (!mesh_model_send(node, src, dst, APP_IDX_DEV_REMOTE, net_idx, - DEFAULT_TTL, data, 20)) + DEFAULT_TTL, false, data, 20)) return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL); return l_dbus_message_new_method_return(msg); @@ -2003,7 +2003,7 @@ static struct l_dbus_message *add_appkey_call(struct l_dbus *dbus, data[3] = app_idx >> 4; if (!mesh_model_send(node, src, dst, APP_IDX_DEV_REMOTE, net_idx, - DEFAULT_TTL, data, 20)) + DEFAULT_TTL, false, data, 20)) return dbus_error(msg, MESH_ERROR_NOT_FOUND, NULL); return l_dbus_message_new_method_return(msg); diff --git a/unit/test-mesh-crypto.c b/unit/test-mesh-crypto.c index 32c46a54e..0043b0b10 100644 --- a/unit/test-mesh-crypto.c +++ b/unit/test-mesh-crypto.c @@ -1017,7 +1017,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) app_msg = l_util_from_hexstring(keys->app_msg, &app_msg_len); if (keys->szmic) { - seg_max = SEG_MAX(app_msg_len + 8); + seg_max = SEG_MAX(keys->segmented, app_msg_len + 8); enc_msg = l_malloc(app_msg_len + 8); mesh_crypto_application_encrypt(key_aid, keys->app_seq, keys->net_src, keys->net_dst, @@ -1028,7 +1028,7 @@ static void check_encrypt(const struct mesh_crypto_test *keys) enc_msg, &app_mic64, sizeof(app_mic64)); l_put_be64(app_mic64, enc_msg + app_msg_len); } else { - seg_max = SEG_MAX(app_msg_len + 4); + seg_max = SEG_MAX(keys->segmented, app_msg_len + 4); enc_msg = l_malloc(app_msg_len + 4); mesh_crypto_application_encrypt(key_aid, keys->app_seq, keys->net_src, keys->net_dst,